Решение на Втора задача от Георги Събев

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

Към профила на Георги Събев

Резултати

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

Код

require 'set'
class Song
attr_accessor :name, :artist, :genre, :subgenre, :tags
def initialize(name, artist, genre, subgenre=nil, tags=[])
@name, @artist, @genre, @subgenre = name, artist, genre, subgenre
@tags = Set.new(tags)
@tags << @genre.downcase
@tags << @subgenre.downcase if @subgenre
end
def matches? criteria
predicate_results = criteria.map { |criterion, value| \
check_criterion criterion, value }
predicate_results.inject(true) { |result, element| result and element}
end
private
def match_tags? tags
tags = [tags] unless tags.kind_of? Enumerable
tags = Set.new(tags.map(&:downcase))
negative = tags.select { |tag| tag.end_with? '!' }
positive = tags - negative
negative = negative.map {|tag| tag.chop }
contains_all_positive = @tags.intersection(positive) == positive
contains_no_negative = @tags.intersection(negative).empty?
contains_all_positive and contains_no_negative
end
def check_criterion criterion, value
case criterion
when :tags then match_tags? value
when :name, :artist then self.send(criterion) == value
when :filter then value.(self)
else true
end
end
end
class Collection
include Enumerable
def initialize(song_as_string, tags={})
@songs = Set.new
song_as_string.lines.each do |line|
name, artist, genre_string, tags_string = split line, /\./
genre, subgenre = split genre_string, /,/
tag_set = Set.new
tag_set += split(tags_string, /,/).to_set if tags_string
tag_set += tags.fetch artist, Set.new
tag_set = tag_set.map(&:downcase)
@songs << Song.new(name, artist, genre, subgenre, tag_set)
end
end
def find criteria={}
self.select { |song| song.matches? criteria }
end
def each
@songs.each { |song| yield song }
end
private
def split string, regex
string.split(regex).map(&:strip) if string
end
end

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

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

Finished in 0.57052 seconds
12 examples, 0 failures

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

Георги обнови решението на 30.10.2011 21:18 (преди около 13 години)

+require 'set'
+
+class Song
+ attr_accessor :name, :artist, :genre, :subgenre, :tags
+
+ def initialize(name, artist, genre, subgenre=nil, tags=[])
+ @name, @artist, @genre, @subgenre = name, artist, genre, subgenre
+ @tags = Set.new(tags)
+ @tags << @genre.downcase
+ @tags << @subgenre.downcase if @subgenre
+ end
+
+ def matches? criteria
+ predicate_results = criteria.map { |criterion, value| \
+ check_criterion criterion, value }
+ predicate_results.inject(true) { |result, element| result and element}
+ end
+
+ private
+
+ def match_tags? tags
+ tags = [tags] unless tags.kind_of? Enumerable
+ tags = Set.new(tags.map(&:downcase))
+ negative = tags.select { |tag| tag.end_with? '!' }
+ positive = tags - negative
+ negative = negative.map {|tag| tag.chop }
+ contains_all_positive = @tags.intersection(positive) == positive
+ contains_no_negative = @tags.intersection(negative).empty?
+ contains_all_positive and contains_no_negative
+ end
+
+ def check_criterion criterion, value
+ case criterion
+ when :tags then match_tags? value
+ when :name, :artist then self.send(criterion) == value
+ when :filter then value.(self)
+ else true
+ end
+ end
+end
+
+class Collection
+ include Enumerable
+
+ def initialize(song_as_string, tags={})
+ @songs = Set.new
+ song_as_string.lines.each do |line|
+ name, artist, genre_string, tags_string = split line, /\./
+ genre, subgenre = split genre_string, /,/
+ tag_set = Set.new
+ tag_set += split(tags_string, /,/).to_set if tags_string
+ tag_set += tags.fetch artist, Set.new
+ tag_set = tag_set.map(&:downcase)
+ @songs << Song.new(name, artist, genre, subgenre, tag_set)
+ end
+ end
+
+ def find criteria={}
+ self.select { |song| song.matches? criteria }
+ end
+
+ def each
+ @songs.each { |song| yield song }
+ end
+
+ private
+
+ def split string, regex
+ string.split(regex).map(&:strip) if string
+ end
+end
+
  • Добре подредено. Харесва ми.
  • В matches? нарушаваш конвенция. Ако блокът ти не е на същия ред, трябва да ползваш do/end, не { }.
  • Отделно, напълно излишно е да екранираш новия ред с \.
  • В Song#initialize си искал да ползваш song_as_string.map.
  • Не мога да разбера нуждата от Collection#split. Гледайки кода ти, не виждам къде го викаш с string = nil. Съответно, не виждам смисъл в if-а.
  • Не ми харесва when :name, :artist then send(criterion). По-добре щеше да е да направиш два отделни блока в case-а. Щеше да се разбира по-лесно. Също така, нямаше да бъде повторение. Важното е да минимизираш повторение на знание, не повторение на символи.
  • self. е излишен на двете места, на които си го написал.

Ще ти дам една бонус точка. Щяха да са две, но онова нарушаване на конвенцията ме спира :)