Тони обнови решението на 27.10.2011 08:43 (преди около 13 години)
+class Song
+ attr_reader :name, :artist, :genre, :subgenre, :tags
+
+ def initialize(name, artist, genre, subgenre, tags)
+ @name = name
+ @artist = artist
+ @genre = genre
+ @subgenre = subgenre
+ @tags = tags
+ end
+
+ def is_desired?(criteria)
+ desired = self.includes_tags? criteria
+ if criteria.include? :name
+ desired = (desired and @name == criteria[:name])
+ end
+ if criteria.include? :artist
+ desired = (desired and @artist == criteria[:artist])
+ end
+ if criteria.include? :filter
+ desired and criteria[:filter][self]
+ else
+ desired
+ end
+ end
+
+ def includes_tags?(criteria)
+ if criteria.include? :tags
+ criteria_tags = Array(criteria[:tags])
+ criteria_tags.all? {|tag| self.has_tag? tag}
+ else
+ true
+ end
+ end
+
+ def has_tag?(tag)
+ if tag.end_with? "!"
+ not @tags.include? tag[0..tag.length - 2]
+ else
+ @tags.include? tag
+ end
+ end
+end
+
+class Collection
+ def initialize(songs_as_string, artist_tags)
+ song_lines = songs_as_string.lines.select {|song_line| song_line.strip}
+ @songs = song_lines.collect{|line| self.parse_song(line, artist_tags)}
+ end
+
+ def parse_song(song_string, artist_tags)
+ attrs = song_string.split(".").collect {|attr| attr.strip}
+ genre_sub = attrs[2].split(",").collect {|attr| attr.strip}
+ genre = genre_sub[0]
+ subgenre = if genre_sub.length > 1 then genre_sub[1] else nil end
+ tags = genre_sub.collect {|attr| attr.downcase}
+ tags |= artist_tags[attrs[1]] if artist_tags.include? attrs[1]
+ tags |= attrs[3].split(",").collect {|attr| attr.strip} if attrs.length > 3
+ Song.new(attrs[0], attrs[1], genre, subgenre, tags)
+ end
+
+ def find(criteria)
+ @songs.select {|song| song.is_desired? criteria}
+ end
+end
+
Малко коментари:
- Тези дълги редове, като в решението ти на първа задача се четат трудно. От втора задача нататък това попада в нещата, за които вземаме точки за лош стил.
- Ако ти подравня кода като хората,
find
няма да минава критерия за 12 реда. - Погледни какво прави
Array(1)
иArray([1, 2])
, би трябвало да опрости един от изразите. - Вместо да правиш масив, да итерираш по
song_strings
и да добавяш резултатите в масива, ползвайmap
.
Имам и още, но искам да видя как и дали ще оправиш тези.
-
Song#is_desired?
няма нужда да акулумира резултат вdesired
. Можеше да ползвашreturn
и да го напишеш в този дух: def is_desired?(criteria) return false unless self.includes_tags? criteria return false if criteria[:name] and @name != criteria[:name] return false if criteria[:artist] and @artist != criteria[:artist] return false if criteria[:filter] and not criteria[:filter][self] true end - Вместо да
slice
-ваш тага сRange
, можеше да напишешtag.chomp('!')
. -
collect {|attr| attr.strip}
се форматира така:collection { |attr| attr.strip }
; по-добре се записва така:collect(&:strip)
. Аналогично за другите. -
subgenre = genre_sub[1]
вместо дългияif then else end
. Щеше да направи абсолютно същото. -
self.
навсякъде е излишно.
Решението ти е кратко, но ако знаеше повече Ruby, щеше да е още по-кратко. Разгледай другите решения и виж какво можеш да научиш.