Решение на Втора задача от Яни Малцев

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

Към профила на Яни Малцев

Резултати

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

Код

class Proc
def &(other)
->( *args) { self[ *args] && other[ *args] }
end
def |(other)
->( *args) { self[ *args] || other[ *args] }
end
end
class Filter
attr :filter
def initialize(&block)
@filter = block
end
def call(x)
@filter.call(x)
end
def |(other)
@filter = @filter | other.filter
self
end
def &(other)
@filter = @filter & other.filter
self
end
end
class TypeFilter < Filter
def initialize(type)
case type
when :integer then @filter = ->(x){ x.is_a?(Integer) }
when :real then @filter = ->(x){ x.is_a?(Float) || x.is_a?(Rational) }
when :complex then @filter = ->(x){ x.is_a?(Complex) }
end
end
end
class SignFilter < Filter
def initialize(sign_type)
case sign_type
when :positive then @filter = ->(x){ x > 0 }
when :non_positive then @filter = ->(x){ x <= 0 }
when :negative then @filter = ->(x){ x < 0 }
when :non_negative then @filter = ->(x){ x >= 0 }
end
end
end
class NumberSet
include Enumerable
def initialize
@data = []
end
def <<(new_element)
@data << new_element unless @data.include? new_element
self
end
def [](filter)
numbers = NumberSet.new
each { | x | numbers << x if filter.call(x) }
numbers
end
def size
@data.size
end
def empty?
@data.size == 0
end
def each
if block_given?
@data.each { |x| yield x}
else
result = @data.to_enum
end
end
end

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

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

Finished in 0.02228 seconds
24 examples, 0 failures

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

Яни обнови решението на 25.10.2014 10:25 (преди над 9 години)

+# ( *args) противоречи със Style Guide, но иначе Skeptic дава грешка
+class Proc
+ def &(other)
+ ->( *args) { self[ *args] && other[ *args] }
+ end
+
+ def |(other)
+ ->( *args) { self[ *args] || other[ *args] }
+ end
+end
+
+module FilterBase
+ attr :filter
+
+ def |(other)
+ @filter = @filter | other.filter
+ self
+ end
+
+ def &(other)
+ @filter = @filter & other.filter
+ self
+ end
+end
+
+class Filter
+ include FilterBase
+
+ def initialize(&block)
+ @filter = ->(x){ block.call x }
+ end
+
+ def call(x)
+ @filter.call(x)
+ end
+end
+
+class TypeFilter
+ include FilterBase
+
+ def initialize(type)
+ case type
+ when :integer then @filter = ->(x){ x.is_a?(Integer) }
+ when :real then @filter = ->(x){ x.is_a?(Float) || x.is_a?(Rational) }
+ when :complex then @filter = ->(x){ x.is_a?(Complex) }
+ end
+ end
+
+ def call(x)
+ @filter.call(x)
+ end
+end
+
+class SignFilter
+ include FilterBase
+
+ def initialize(sign_type)
+ case sign_type
+ when :positive then @filter = ->(x){ x > 0 }
+ when :non_positive then @filter = ->(x){ x <= 0 }
+ when :negative then @filter = ->(x){ x < 0 }
+ when :non_negative then @filter = ->(x){ x >= 0 }
+ end
+ end
+
+ def call(x)
+ @filter.call(x)
+ end
+end
+
+class NumberSet
+ include Enumerable
+
+ def initialize
+ @data = []
+ end
+
+ def <<(new_element)
+ @data << new_element if ! @data.include? new_element
+ self
+ end
+
+ def [](filter)
+ numbers = NumberSet.new
+ each { | x | numbers << x if filter.call(x) }
+ numbers
+ end
+
+ def size
+ @data.size
+ end
+
+ def empty?
+ @data.size == 0
+ end
+
+ def each
+ @data.each { |x| yield x}
+ end
+end

Здрасти,

Няколко неща, които забелязвам в кода ти:

  • НЕ ползвай self[ *args] за извикване на анонимна функция. self.call *args е същото, даже можеш да изпуснеш self. Варианта със счупените скоби е този, който най-малко харесваме от трите.
  • Пробвай без да monkey patch-ваш Proc. Не е добре да променяш обект, който се ползва буквално на всеки втори ред в Ruby. :)
  • Защо реши да ползваш mixin? Не може ли вместо FilterBase модула да имплементираш тези методи във Filter и да оставиш TypeFilter и SignFilter да го наследят? Защо call не е част от mixin-а при положение, че се повтаря и в трите?
  • @filter = ->(x){ block.call x } е почти същото като @filter = block. В твоя случай второто ще работи и ще е малко по-кратко/ясно.
  • if ! @data.include? new_element е другия вариант да напишеш unless @data.include? new_element. По мое мнение второто е по-четимо.
  • Провери как работи Array#each, когато не му подадеш блок. Очакваме NumberSet#each да работи по същия начин.

Честно казано и на мен ми се искаше да го направя по друг начин с *args но при опит да махна скобите или да го извикам без self ето какви са ми съответните резултати:

Screenshot

С това се сблъсках още докато го писах, но така и неразбрах защо се получава. Единсвено когато е със self и [] работи нормално. Отлкото за другите забележки, много благодаря, че ги отбелязахте - особено как мога да избегна копирането на "call" чрез наследяването(преди проблема беше че при "include" не се наследяваше правилно и при извикването на call в [] даваше грешка).

Яни обнови решението на 26.10.2014 15:25 (преди над 9 години)

-# ( *args) противоречи със Style Guide, но иначе Skeptic дава грешка
class Proc
def &(other)
->( *args) { self[ *args] && other[ *args] }
end
def |(other)
->( *args) { self[ *args] || other[ *args] }
end
end
-module FilterBase
+
+class Filter
attr :filter
+ def initialize(&block)
+ @filter = block
+ end
+
+ def call(x)
+ @filter.call(x)
+ end
+
def |(other)
@filter = @filter | other.filter
self
end
def &(other)
@filter = @filter & other.filter
self
end
end
-class Filter
- include FilterBase
-
- def initialize(&block)
- @filter = ->(x){ block.call x }
- end
-
- def call(x)
- @filter.call(x)
- end
-end
-
-class TypeFilter
- include FilterBase
-
+class TypeFilter < Filter
def initialize(type)
case type
when :integer then @filter = ->(x){ x.is_a?(Integer) }
when :real then @filter = ->(x){ x.is_a?(Float) || x.is_a?(Rational) }
when :complex then @filter = ->(x){ x.is_a?(Complex) }
end
end
-
- def call(x)
- @filter.call(x)
- end
end
-class SignFilter
- include FilterBase
-
+class SignFilter < Filter
def initialize(sign_type)
case sign_type
when :positive then @filter = ->(x){ x > 0 }
when :non_positive then @filter = ->(x){ x <= 0 }
when :negative then @filter = ->(x){ x < 0 }
when :non_negative then @filter = ->(x){ x >= 0 }
end
end
-
- def call(x)
- @filter.call(x)
- end
end
class NumberSet
include Enumerable
def initialize
@data = []
end
def <<(new_element)
- @data << new_element if ! @data.include? new_element
+ @data << new_element unless @data.include? new_element
self
end
def [](filter)
numbers = NumberSet.new
each { | x | numbers << x if filter.call(x) }
numbers
end
def size
@data.size
end
def empty?
@data.size == 0
end
def each
- @data.each { |x| yield x}
+ if block_given?
+ @data.each { |x| yield x}
+ else
+ result = @data.to_enum
+ end
end
-end
+end