Михаил обнови решението на 30.10.2011 03:48 (преди около 13 години)
+class Collection
+ def initialize songs, additional_tags
+ @collection = songs.lines.map{ |line| Song.new *line.split(".") }
+ additional_tags.each do |artist, tags|
+ find(artist: artist).each { |song| song.tags += tags }
+ end
+ end
+
+ def find criterias
+ filters = []
+ fields = [:name,:artist,:genre,:subgenre].select{ |field| criterias[field] }
+ filters += fields.map{ |field| field_filter field, criterias[field] }
+ filters += tags_filters(*criterias[:tags]) if criterias[:tags]
+ filters << criterias[:filter] if criterias[:filter]
+ filter = ->(song) { filters.all? { |filter| filter.call song }}
+ @collection.select{ |song| filter.call song }
+ end
+
+ private
+
+ def field_filter field, value
+ ->(song) { song.send(field) == value }
+ end
+
+ def tags_filters *tags
+ tags.map { |tag| tag_filter tag}
+ end
+
+ def tag_filter tag
+ tag, exclude = tag[0..-2], true if tag.end_with? '!'
+ ->(song) { song.tags.include?(tag) ^ exclude }
+ end
+end
+
+class Song
+ attr_accessor :name, :artist, :genre, :subgenre, :tags
+
+ def initialize name, artist, genres, tags = ""
+ @name,@artist = name.strip, artist.strip
+ @genre,@subgenre = genres.split(",").map{ |genre| genre.strip }
+ @tags = tags.split( ",").map{ |tag| tag.strip.downcase }
+ @tags << @genre.downcase
+ @tags << @subgenre.downcase if @subgenre
+ end
+end
Ето малко коментари:
- Няма дума "criterias". "criteria" е множественото число на "criterion".
- Слага се интервал между
map
и{
. - Метод се дефинира така
def tags_filter(*tags)
. Със скоби. Не се слагат два интервала между метода и параметрите му. - Решението да връщаш ламбда е интересно, макар и не съвсем оптимално.
- На места отделяш думите с произволно количество интервали.
criterias[:filter] if criterias[:filter]
иcriterias[:filter] if criterias[:filter]
. Това не е ОК. - Всъщност, на ред произволни места си сложил интервали в които няма никаква логика.
tags.split( ",")
например. - Тялото на
tags_filters
е подравнено с три интервала. Трябва да бъде два. Бих взел точки, но е само тук. - Парсенето ти е малко странно. Става между
Song#initialize
иCollection#initialize
. Това е лошо. Добре е само един метод да знае как се парси ред. По-добре е да бъде вCollection
. - Заради горното, конструктора ти на
Song
е крив. Трябваше или да взема пет аргумента, или да взема един ред. -
map { |genre| genre.strip }
се записва катоmap(&:strip)
. - Браво, че си се сетил за
song.tags.include?(tag) ^ exclude
Иначе, решението ти е приятно и кратко. Харесва ми. Ще ти дам 1 допълнителна точка. Щяха да са три, но разхвърляните интервали и лошия whitespace ме спира.
Благодаря.
Предполагам че интервалите (тук и там и където и да е ) идват от това че решението е от Събота (в почти тази му форма) и след това само съм местил и заменял някои работи както и преименувал променливи до Понеделник... Очевидно трябва да правя :set list
от време на време.
п.п. в сегашната задача се оказа че имам някакви странни whitespace-ове след половината от редовете. Благодаря отново.