Решение на Втора задача от Михаил Стойков

Обратно към всички решения

Към профила на Михаил Стойков

Резултати

  • 6 точки от тестове
  • 1 бонус точка
  • 7 точки общо
  • 12 успешни тест(а)
  • 0 неуспешни тест(а)

Код

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

Лог от изпълнението

............

Finished in 0.54779 seconds
12 examples, 0 failures

История (1 версия и 2 коментара)

Михаил обнови решението на 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-ове след половината от редовете. Благодаря отново.