Решение на Втора задача от Атанас Димитров

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

Към профила на Атанас Димитров

Резултати

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

Код

class NumberSet
include Enumerable
def initialize(array: [])
@numbers = array
end
def <<(number)
@numbers << number unless @numbers.include? number
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def each(&block)
@numbers.each(&block)
end
def [](filter)
NumberSet.new array: @numbers.select { |number| filter.approve? number }
end
end
class Filter
def initialize(&block)
@condition = block
end
def approve?(number)
@condition.call number
end
def &(other_filter)
Filter.new { |number| approve? number and other_filter.approve? number }
end
def |(other_filter)
Filter.new { |number| approve? number or other_filter.approve? number }
end
end
class TypeFilter < Filter
def initialize(number_type)
case number_type
when :integer
super() { |number| number.kind_of? Integer }
when :complex
super() { |number| number.kind_of? Complex }
else
super() { |number| number.kind_of? Rational or number.kind_of? Float }
end
end
end
class SignFilter < Filter
def initialize(compared_to_zero)
case compared_to_zero
when :positive then super() { |number| number > 0 }
when :non_positive then super() { |number| number <= 0 }
when :negative then super() { |number| number < 0 }
else super() { |number| number >= 0 }
end
end
end

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

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

Finished in 0.02297 seconds
24 examples, 0 failures

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

Атанас обнови решението на 25.10.2014 13:05 (преди около 10 години)

+class NumberSet
+ include Enumerable
+ def initialize(array: [])
+ @container = array
+ end
+
+ def <<(number)
+ @container.each do |element|
+ if element == number
+ return
+ end
+ end
+ @container << number
+ end
+
+ def size
+ @container.size
+ end
+
+ def empty?
+ @container.empty?
+ end
+
+ def each(&condition)
+ @container.each(&condition)
+ end
+
+ def [](filter)
+ NumberSet.new array: @container.select { |element| filter.sieve element }
+ end
+end
+
+class Filter
+ def initialize(&condition)
+ @condition = condition
+ end
+
+ def sieve(element)
+ @condition.call element
+ end
+
+ def &(other_filter)
+ Filter.new { |element| sieve element and other_filter.sieve element }
+ end
+
+ def |(other_filter)
+ Filter.new { |element| sieve element or other_filter.sieve element }
+ end
+end
+
+class TypeFilter < Filter
+ def initialize(number_type)
+ case number_type
+ when :integer then @condition = ->(element) { element.kind_of? Integer }
+ when :complex then @condition = ->(element) { element.kind_of? Complex }
+ else @condition = lambda do |element|
+ element.kind_of? Rational or element.kind_of? Float
+ end
+ end
+ end
+end
+
+class SignFilter < Filter
+ def initialize(compared_to_zero)
+ case compared_to_zero
+ when :positive then @condition = ->(element) { element > 0 }
+ when :non_positive then @condition = ->(element) { element <= 0 }
+ when :negative then @condition = ->(element) { element < 0 }
+ when :non_negative then @condition = ->(element) { element >= 0 }
+ end
+ end
+end

Здрасти,

Ето няколко неща от мен:

  • Празен ред след include Enumerable.
  • Има по-елегантен начин да напишеш NumberSet#<<. Проверката, която правиш вече е реализирана, преизползвай я.
  • До колкото разбирам Filter#sieve връща булева стойност. Имаме конвенция за иментата на такива методи. Помисли за по-добро такова. :)
  • Предлагам ти да кръщаваш блок параметрите си &block освен, ако няма наистина смислена причина да е друго. condition не е много коректно име.
  • В TypeFilterSignFilter) можеш да замениш присвояването на стойност на @condition с подаване на блок на конструктора на Filter. super() { |number| ... }.
  • Предпочитай number пред element, numbers пред container. В контекста на числа това са много по-ясни имена. Абстрактните имена не са много полезни. :)

Това е. Браво иначе, добро решение! :)

Атанас обнови решението на 25.10.2014 19:55 (преди около 10 години)

class NumberSet
include Enumerable
+
def initialize(array: [])
- @container = array
+ @numbers = array
end
def <<(number)
- @container.each do |element|
- if element == number
- return
- end
- end
- @container << number
+ @numbers << number unless @numbers.include? number
end
def size
- @container.size
+ @numbers.size
end
def empty?
- @container.empty?
+ @numbers.empty?
end
- def each(&condition)
- @container.each(&condition)
+ def each(&block)
+ @numbers.each(&block)
end
def [](filter)
- NumberSet.new array: @container.select { |element| filter.sieve element }
+ NumberSet.new array: @numbers.select { |number| filter.approve? number }
end
end
class Filter
- def initialize(&condition)
- @condition = condition
+ def initialize(&block)
+ @condition = block
end
- def sieve(element)
- @condition.call element
+ def approve?(number)
+ @condition.call number
end
def &(other_filter)
- Filter.new { |element| sieve element and other_filter.sieve element }
+ Filter.new { |number| approve? number and other_filter.approve? number }
end
def |(other_filter)
- Filter.new { |element| sieve element or other_filter.sieve element }
+ Filter.new { |number| approve? number or other_filter.approve? number }
end
end
class TypeFilter < Filter
def initialize(number_type)
case number_type
- when :integer then @condition = ->(element) { element.kind_of? Integer }
- when :complex then @condition = ->(element) { element.kind_of? Complex }
- else @condition = lambda do |element|
- element.kind_of? Rational or element.kind_of? Float
- end
+ when :integer
+ super &(->(number) { number.kind_of? Integer })
+ when :complex
+ super &(->(number) { number.kind_of? Complex })
+ else
+ super &(->(number) { number.kind_of? Rational or number.kind_of? Float })
end
end
end
class SignFilter < Filter
def initialize(compared_to_zero)
case compared_to_zero
- when :positive then @condition = ->(element) { element > 0 }
- when :non_positive then @condition = ->(element) { element <= 0 }
- when :negative then @condition = ->(element) { element < 0 }
- when :non_negative then @condition = ->(element) { element >= 0 }
+ when :positive then super &(->(number) { number > 0 })
+ when :non_positive then super &(->(number) { number <= 0 })
+ when :negative then super &(->(number) { number < 0 })
+ else super &(->(number) { number >= 0 })
end
end
end

Този начин на подаване на блок е доста неприятен, тъй като си има хубав синтаксис за него:

when foo then super &(-> (number) { ... })

По-добре е да е така:

when foo then super { |number| ... }

Смятам, че си съгласен, че така е много по-добре :)

Аз подозирам защо си го направил по този наичн. Вероятно проблемът ти е с аргументите. Един начин би бил просто да приемеш аргумент и в конструктора на базовия клас – Filter#initialize, който да игнорираш. Например, def initialize(_, &block). Друг вариант е да позволиш произволен брой аргументи, например така: def initialize(*_, &block). Но правилният начин всъщност е друг.

super е специална ключова дума в езика. Извиква родителската версия на метода. Поведението на кръглите скоби след извикване на super е малко по-различно от всички останали методи. Когато няма кръгли скоби и няма подадени аргументи, какъвто би бил случаят с подаване на блок като синтаксис, тогава super просто предава аргументите на текущия метод към родителската версия, без да ги пипа. Ако искаш да промениш това поведение, слагаш параметри и/или кръгли скоби.

Тоест, правилното решение на проблема би било:

when foo then super() { |number| ... }

Атанас обнови решението на 26.10.2014 18:59 (преди около 10 години)

class NumberSet
include Enumerable
def initialize(array: [])
@numbers = array
end
def <<(number)
@numbers << number unless @numbers.include? number
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def each(&block)
@numbers.each(&block)
end
def [](filter)
NumberSet.new array: @numbers.select { |number| filter.approve? number }
end
end
class Filter
def initialize(&block)
@condition = block
end
def approve?(number)
@condition.call number
end
def &(other_filter)
Filter.new { |number| approve? number and other_filter.approve? number }
end
def |(other_filter)
Filter.new { |number| approve? number or other_filter.approve? number }
end
end
class TypeFilter < Filter
def initialize(number_type)
case number_type
when :integer
- super &(->(number) { number.kind_of? Integer })
+ super() { |number| number.kind_of? Integer }
when :complex
- super &(->(number) { number.kind_of? Complex })
+ super() { |number| number.kind_of? Complex }
else
- super &(->(number) { number.kind_of? Rational or number.kind_of? Float })
+ super() { |number| number.kind_of? Rational or number.kind_of? Float }
end
end
end
class SignFilter < Filter
def initialize(compared_to_zero)
case compared_to_zero
- when :positive then super &(->(number) { number > 0 })
- when :non_positive then super &(->(number) { number <= 0 })
- when :negative then super &(->(number) { number < 0 })
- else super &(->(number) { number >= 0 })
+ when :positive then super() { |number| number > 0 }
+ when :non_positive then super() { |number| number <= 0 }
+ when :negative then super() { |number| number < 0 }
+ else super() { |number| number >= 0 }
end
end
end