Решение на Втора задача от Иван Арабаджиев

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

Към профила на Иван Арабаджиев

Резултати

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

Код

require 'set'
class Song
attr_reader :genre, :subgenre
def initialize(song_string, extra_tags)
@name, @artist, @genre, @tags = song_string.split('.').map(&:strip)
@tags = "#{@tags},#{@genre.downcase}".split(',').map(&:strip)
@tags = (@tags + extra_tags.fetch(@artist, []) - ['']).uniq
@genre, @subgenre = @genre.split(',').map(&:strip)
self
end
def name(compare_with = nil)
compare_with.nil? ? @name : @name == compare_with
end
def artist(compare_with = nil)
compare_with.nil? ? @artist : @artist == compare_with
end
def tags(compare_with = nil)
return @tags if compare_with.nil?
compare_with = [compare_with].flatten
compare_with.all? do |tag|
tag.end_with?('!') != (@tags.include?tag.chomp('!'))
end
end
def filter(saint_lambda)
saint_lambda.call self
end
end
class Collection
def initialize(songs_string, extra_tags)
@songs = songs_string.lines.map { |line| Song.new(line, extra_tags) }
end
def find(criteria)
@songs.select do |the_song|
criteria.all? { |field, value| the_song.method(field).call(value) }
end
end
end

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

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

Finished in 0.55663 seconds
12 examples, 0 failures

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

Иван обнови решението на 28.10.2011 09:55 (преди над 12 години)

+require 'set'
+
+class Song
+ attr_reader :genre, :subgenre
+ def initialize(song_string, extra_tags)
+ @name, @artist, @genre, @tags = song_string.split('.').map(&:strip)
+ @tags = "#{@tags},#{@genre.downcase}".split(',').map(&:strip)
+ @tags = (@tags + extra_tags.fetch(@artist, []) - ['']).uniq
+ @genre, @subgenre = @genre.split(',').map(&:strip)
+ self
+ end
+
+ def name(compare_with = nil)
+ compare_with.nil? ? @name : @name == compare_with
+ end
+
+ def artist(compare_with = nil)
+ compare_with.nil? ? @artist : @artist == compare_with
+ end
+
+ def tags(compare_with = nil)
+ return @tags if compare_with.nil?
+ compare_with = [compare_with].flatten
+ compare_with.all? do |tag|
+ tag.end_with?('!') != (@tags.include?tag.chomp('!'))
+ end
+ end
+
+ def filter(saint_lambda)
+ saint_lambda.call self
+ end
+end
+
+class Collection
+ def initialize(songs_string, extra_tags)
+ @songs = songs_string.lines.map { |line| Song.new(line, extra_tags) }
+ end
+
+ def find(criteria)
+ @songs.select do |the_song|
+ criteria.all? { |field, value| the_song.method(field).call(value) }
+ end
+ end
+end

Доста по-добре от останалите, но ето ти малко коментари все пак:

  • В момента Collection е глупав. Той е по-подходящ да парси редовете от Song.
  • @my_song_list е далеч по-лошо име от @songs.
  • attr_reader :genre, :subgenre.
  • Странно е #name едновременно да връща името и да проверява дали песента има такова име. По-добре това да са два отделни метода.
  • Ако искаш да вземеш всичко без последната удивителна на низ, това може да стане със str.chomp('!')
  • saint_lambda?
  • По-добре създавай нов списък от тагове, вместо да го мутираш @tags = @tags.uniq.

Няма да се разсърдим, ако си сложиш снимка :)

Тъй, понеже обещах да си опиша официално коментарите - 'here goes nothin' :)

Съгласен съм със забележките отностно @my_song_list, attr_reader, str#chomp и мутирането на @tags - оправил съм ги в решението.

Collection е ужасяващо глупав, но не искам да дробя редовете в него. От тук произтича, че не мога и допълните тагове да пъхам от там (ако не съм извадил artist не мога да си харесам конкретна стойност от hash-a)

saint_lambda не е нито криптично, нито кратко, нито подвеждащо - приеми го като 'моя подпис' в/у тоя сорс. Ако те дразни много - ще се постарая следващите задачи да са с по-скучни аргументи:)

По принцип поведението на атрибутите на Song е странно, но към момента не се сещам друг начин, който да ми позволява толкова проста реализация на find. Идеята ми е, че търсех конструкция, в която да сравнявам с

class.func(param)==criteria[param]

и не си харесах друг начин да го реализирам (поне без специална обработка на criteria[filter]).

@tags = "#{@tags},#{@genre.downcase}.split(',') - отново идва от нежеланието ми да раздробявам tags и genre/subgenre по-рано. В този момент те не са масиви от думички, а списъци от думички (разделени в 1 стринг с ,) -> Така с 1 удар хващам 2 мухи, вместо да парсвам 2 различни списъка по един и същи начин.

За not (x==y) се извинявам, че съм те разбрал грешно и съм го оправил:)

ПС Последната снимка, която ми е направена доброволно е с две котенца някъде в планината (преди >2 години). Мразя да се снимам и този курс не е основателна причина да се жертвам (нищо лично, ама наистина много много мразя да се снимам) :)

Мерси, принципно се размислих, че мога да превърна

def find(criteria)
  @songs.select do |the_song| 
    criteria.all? { |field, value| the_song.method(field).call(value) }
  end
end

В

def find(criteria)
  @songs.select do |the_song| 
    criteria.all? { |field, value| the_song.method("check_#{field}").call(value) }
  end
end

И да постигна същото с класови атрибути

ПС saint_lamba е света ламбда, ако беше holy_lambda щеше да е свещена :)

По принцип знам (в смисъл внимавам на лекции), но когато го писах ми направи някакъв проблем. Възможно да е идвал от другаде, но като достигнах някаква стабилност ми се стори по-умно да не го пипам :)

Не съм ходил на Python (не помня с какво се настъпваше)