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

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

Към профила на Здравко Стойчев

Резултати

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

Код

class Song
attr_reader :name, :artist, :genre, :subgenre, :tags
def initialize(name, artist, genre, subgenre, tags)
@name, @artist, @tags = name, artist, tags
@genre, @subgenre = genre, subgenre
end
def matches?(criteria)
criteria.all? do |type, value|
case type
when :name then name == value
when :artist then artist == value
when :filter then value.(self)
when :tags then Array(value).all? { |tag| matches_tag? tag }
end
end
end
def matches_tag?(tag)
tag.end_with?("!") ^ tags.include?(tag.chomp "!")
end
end
class Collection
def initialize(songs_string, artist_tags)
@collection = songs_string.lines.map { |song| song.split(".").map(&:strip) }
@collection.map! do |name, artist, genres_string, tags_string|
genre, subgenre = genres_string.split(",").map(&:strip)
tags = artist_tags.fetch(artist, [])
tags += [genre, subgenre].compact.map(&:downcase)
tags += tags_string.split(",").map(&:strip) unless tags_string.nil?
Song.new(name, artist, genre, subgenre, tags)
end
end
def find(criteria)
@collection.select { |song| song.matches?(criteria) }
end
end

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

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

Finished in 0.54292 seconds
12 examples, 0 failures

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

Здравко обнови решението на 27.10.2011 11:42 (преди над 12 години)

+class Song
+ attr_reader :name, :artist, :genre, :subgenre, :tags
+
+ def initialize(name, artist, genre, subgenre, tags)
+ @name, @artist, @tags = name, artist, tags
+ @genre, @subgenre = genre, subgenre
+ end
+
+ def matches?(criteria)
+ criteria.all? do |type, value|
+ case type
+ when :name then name == value
+ when :artist then artist == value
+ when :filter then value.(self)
+ when :tags then Array(value).all? { |tag| matches_tag? tag }
+ end
+ end
+ end
+
+ def matches_tag?(tag)
+ tag.end_with?("!") ^ tags.include?(tag.chomp "!")
+ end
+end
+
+class Collection
+ def initialize(songs_string, artist_tags)
+ @collection = songs_string.lines.map { |song| song.split(".").map(&:strip) }
+ @collection.map! do |name, artist, genres_string, tags_string|
+ genre, subgenre = genres_string.split(",").map(&:strip)
+ tags = artist_tags.fetch(artist, [])
+ tags += [genre, subgenre].compact.map(&:downcase)
+ tags += tags_string.split(",").map(&:strip) unless tags_string.nil?
+
+ Song.new(name, artist, genre, subgenre, tags)
+ end
+ end
+
+ def find(criteria)
+ @collection.select { |song| song.matches?(criteria) }
+ end
+end

Ето коментари. Добавил съм едни подсказки в условието, но ще ги повторя тук. Погледни ги все пак.

  • Макар кодът ти да е кратък, добре е проверката дали песен отговаря на условието на е в Song. Иначе Song е много глупав клас.
  • tag.end_with?("!") ^ song.tags.include?(tag.chomp "!") е хитро решение. И аз съм написал това. Можеш да опростиш дясната част още.
  • Този стил с хилядите ламбди е гаден, защото е труден за четене. Можеш просто да минеш с един case.
  • Странно е да обхождаш всички критерии и инкрементално да променяш @result. По-добре го сведи до @collection.select { |song| song.matches? criteria }.
  • Тези ред с criterion_to_condition е безумно дълъг. За това вземаме точки.
  • Правиш твърде много split-ове. Ако ще ползваш регулярни изрази, можеш да минеш с един.
  • Отново, виж подсказките.

Можеш да оправиш тези неща и ще ти дадем точки.

Благодаря :). Не успях да измисля как би могло да стане само с един split. Би могло с един регулярен израз, но май ще е прекалено сложен. Между другото забелязах, че условието не казва ясно, че преди разделителите със сигурност няма whitespace, както съм приел в моето решение. Правилно ли съм приел или да поправя сплитовете на split(".").map(&:strip)?

Благодаря!

И мен map! не ми харесва и доста се чудих как да го направя. Първоначално го бях поправил на:

songs = ...
@collection = songs.map...

В случая, обаче, songs и collection са почти синоними като имена и изглежда малко объркващо. Най-добре щеше да е да измисля по-добро име за songs, но измислях само прекалено дълги. Затова реших да конструирам @collection на стъпки, подобно на tags. Чудех се между map! и

@collection = ...
@collection = @collection.map...

Кой от всичките варианти щеше да е най-добър?