Решение на Втора задача от Кирил Владимиров

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

Към профила на Кирил Владимиров

Резултати

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

Код

class Song
attr_accessor :name, :artist, :album
def initialize(hash)
@name = hash[:name].chomp
@artist = hash[:artist].chomp
@album = hash[:album].chomp
end
def to_hash
{ name: @name, artist: @artist, album: @album }
end
end
class Collection
include Enumerable
attr_accessor :songs
def initialize(songs)
@songs = songs
end
def each
@songs.each { |song| yield song }
end
def self.parse(text)
songs = text.lines.each_slice(4).to_a.map do |song|
Song.new({ name: song[0], artist: song[1], album: song[2] })
end
new songs
end
def names
@songs.map { |song| song.name }.uniq
end
def artists
@songs.map { |song| song.artist }.uniq
end
def albums
@songs.map { |song| song.album }.uniq
end
def adjoin(collection)
Collection.new(@songs | collection.songs)
end
def filter(criteria)
return self if criteria.rules.length == 0
return Filter.get(self, criteria.rules[0]) unless criteria.rules[1]
Filter.send(criteria.rules[1], self, criteria)
end
end
class Filter
def self.evaluate_first_criterion(collection, rules)
if rules[0].kind_of? Array
Collection.new rules[0]
else
get collection, rules
end
end
def self.conjunction(collection, criteria)
first = Filter.evaluate_first_criterion collection, criteria.rules.first
second = get collection, criteria.rules[2]
result = Collection.new(first.songs & second.songs)
result.filter(Criteria.new(criteria.rules[3..criteria.rules.length]))
end
def self.disjunction(collection, criteria)
first = Filter.evaluate_first_criterion collection, criteria.rules.first
second = get collection, criteria.rules[2]
new_collection = first.reject { |song| not second.include? song }
Collection.new(new_collection).filter(Criteria.new(rules[3..rules.length]))
end
def self.get(collection, rule)
Collection.new(collection.songs.select do |song|
(song.send(rule[:field]) == rule[:value]) == rule[:has]
end)
end
end
class Criteria
include Enumerable
attr_accessor :rules
def initialize(rules)
@rules = rules
end
def each
@rules.each { |rule| yield rule }
end
def self.name(value)
Criteria.new [{has: true, field: 'name', value: value}]
end
def self.artist(value)
Criteria.new [{has: true, field: 'artist', value: value}]
end
def self.album(value)
Criteria.new [{has: true, field: 'album', value: value}]
end
def |(other)
Criteria.new(@rules + ['disjunction', other.rules].flatten)
end
def &(other)
Criteria.new(@rules + ['conjunction', other.rules].flatten)
end
def !
new_rules = @rules.clone
new_rules.each { |rule| rule.kind_of? Hash and rule[:has] = !rule[:has] }
Criteria.new new_rules
end
end

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

........F..

Failures:

  1) Collection supports a disjunction of filters
     Failure/Error: filtered = collection.filter Criteria.artist('Sting') | Criteria.name('Fields of Gold')
     NameError:
       undefined local variable or method `rules' for Filter:Class
     # /tmp/d20130203-23049-1ilha7i/solution.rb:77:in `disjunction'
     # /tmp/d20130203-23049-1ilha7i/solution.rb:53:in `filter'
     # /tmp/d20130203-23049-1ilha7i/spec.rb:69:in `block (2 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.01046 seconds
11 examples, 1 failure

Failed examples:

rspec /tmp/d20130203-23049-1ilha7i/spec.rb:68 # Collection supports a disjunction of filters

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

Кирил обнови решението на 29.10.2012 00:11 (преди около 12 години)

+class Song
+ attr_accessor :name, :artist, :album
+
+ def initialize(hash)
+ @name = hash[:name].chomp
+ @artist = hash[:artist].chomp
+ @album = hash[:album].chomp
+ end
+end
+
+class Collection
+ include Enumerable
+
+ def initialize(songs)
+ @songs = songs
+ end
+
+ def each
+ @songs.each { |song| yield song }
+ end
+
+ def self.parse(text)
+ songs = text.lines.each_slice(4).to_a.map do |song|
+ Song.new({ name: song[0], artist: song[1], album: song[2] })
+ end
+ self.new songs
+ end
+
+ def names
+ @songs.map { |song| song.name }.uniq
+ end
+
+ def artists
+ @songs.map { |song| song.artist }.uniq
+ end
+
+ def albums
+ @songs.map { |song| song.album }.uniq
+ end
+end
+

Кирил обнови решението на 31.10.2012 14:51 (преди около 12 години)

class Song
- attr_accessor :name, :artist, :album
+ attr_accessor :name, :artist, :album
- def initialize(hash)
- @name = hash[:name].chomp
- @artist = hash[:artist].chomp
- @album = hash[:album].chomp
- end
+ def initialize(hash)
+ @name = hash[:name].chomp
+ @artist = hash[:artist].chomp
+ @album = hash[:album].chomp
+ end
+
+ def to_hash
+ { name: @name, artist: @artist, album: @album }
+ end
end
class Collection
- include Enumerable
+ include Enumerable
+ attr_accessor :songs
- def initialize(songs)
- @songs = songs
- end
+ def initialize(songs)
+ @songs = songs
+ end
- def each
- @songs.each { |song| yield song }
- end
+ def each
+ @songs.each { |song| yield song }
+ end
- def self.parse(text)
- songs = text.lines.each_slice(4).to_a.map do |song|
- Song.new({ name: song[0], artist: song[1], album: song[2] })
- end
- self.new songs
+ def self.parse(text)
+ songs = text.lines.each_slice(4).to_a.map do |song|
+ Song.new({ name: song[0], artist: song[1], album: song[2] })
end
+ new songs
+ end
- def names
- @songs.map { |song| song.name }.uniq
- end
+ def names
+ @songs.map { |song| song.name }.uniq
+ end
- def artists
- @songs.map { |song| song.artist }.uniq
- end
+ def artists
+ @songs.map { |song| song.artist }.uniq
+ end
- def albums
- @songs.map { |song| song.album }.uniq
+ def albums
+ @songs.map { |song| song.album }.uniq
+ end
+
+ def adjoin(collection)
+ Collection.new(@songs | collection.songs)
+ end
+
+ def filter(criteria)
+ return self if criteria.rules.length == 0
+ return Filter.get(self, criteria.rules[0]) unless criteria.rules[1]
+ Filter.send(criteria.rules[1], self, criteria)
+ end
+end
+
+class Filter
+ def self.evaluate_first_criterion(collection, rules)
+ if rules[0].kind_of? Array
+ Collection.new rules[0]
+ else
+ get collection, rules
end
+ end
+
+ def self.conjunction(collection, criteria)
+ first = Filter.evaluate_first_criterion collection, criteria.rules.first
+ second = get collection, criteria.rules[2]
+ result = Collection.new(first.songs & second.songs)
+ result.filter(Criteria.new(criteria.rules[3..criteria.rules.length]))
+ end
+
+ def self.disjunction(collection, criteria)
+ first = Filter.evaluate_first_criterion collection, criteria.rules.first
+ second = get collection, criteria.rules[2]
+ new_collection = first.reject { |song| not second.include? song }
+ Collection.new(new_collection).filter(Criteria.new(rules[3..rules.length]))
+ end
+
+ def self.get(collection, rule)
+ Collection.new(collection.songs.select do |song|
+ (song.send(rule[:field]) == rule[:value]) == rule[:has]
+ end)
+ end
end
+class Criteria
+ include Enumerable
+ attr_accessor :rules
+
+ def initialize(rules)
+ @rules = rules
+ end
+
+ def each
+ @rules.each { |rule| yield rule }
+ end
+
+ def self.name(value)
+ Criteria.new [{has: true, field: 'name', value: value}]
+ end
+
+ def self.artist(value)
+ Criteria.new [{has: true, field: 'artist', value: value}]
+ end
+
+ def self.album(value)
+ Criteria.new [{has: true, field: 'album', value: value}]
+ end
+
+ def |(other)
+ Criteria.new(@rules + ['disjunction', other.rules].flatten)
+ end
+
+ def &(other)
+ Criteria.new(@rules + ['conjunction', other.rules].flatten)
+ end
+
+ def !
+ new_rules = @rules.clone
+ new_rules.each { |rule| rule.kind_of? Hash and rule[:has] = !rule[:has] }
+ Criteria.new new_rules
+ end
+end

I hate myself...

В тоя ред на мисли, излъгах skeptic-а.

new_rules.each { |rule| rule.kind_of? Hash and rule[:has] = !rule[:has] }

Часта преди and-а беше като if след самата операция за присвояване, но ме спря заради ниво на влагане. Не съм сигурен дали това изобщо може/трябва да се фиксва, но да знаеш.

П.П.: Очевидно е, че мога да итерирам по-адекватно, но все пак.