Решение на Втора задача от Веселин Добрев
Резултати
- 6 точки от тестове
- 0 бонус точки
- 6 точки общо
- 24 успешни тест(а)
- 0 неуспешни тест(а)
Код
require 'forwardable'
class NumberSet
extend Forwardable
include Enumerable
def initialize
@numbers = []
end
def <<(number)
@numbers << number unless @numbers.include? number
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def [](filter)
reduced_set = NumberSet.new
@numbers.select { |number| filter.passes? number }.each do |number|
reduced_set << number
end
reduced_set
end
def_delegator :@numbers, :each
end
class Filter
def initialize(&block)
@block = block
end
def passes?(number)
@block.call(number)
end
def &(other_filter)
Filter.new { |number| passes? number and other_filter.passes? number}
end
def |(other_filter)
Filter.new { |number| passes? number or other_filter.passes? number}
end
end
class TypeFilter < Filter
def initialize(type)
@type = type
end
def passes?(number)
case @type
when :integer then number.is_a? Fixnum
when :real then number.is_a? Float or number.is_a? Rational
when :complex then number.is_a? Complex
end
end
end
class SignFilter < Filter
def initialize(sign)
@sign = sign
end
def passes?(number)
case @sign
when :positive then number > 0
when :negative then number < 0
when :non_negative then number >= 0
when :non_positive then number <= 0
end
end
end
Лог от изпълнението
........................ Finished in 0.02238 seconds 24 examples, 0 failures
История (5 версии и 5 коментара)
+class NumberSet
+ include Enumerable
+
+ def initialize
+ @numbers = Array.new
+ end
+
+ def <<(number)
+ @numbers << number if ! @numbers.include? number
+ end
+
+ def size
+ @numbers.size
+ end
+
+ def empty?
+ @numbers.empty?
+ end
+
+ def [](filter)
+ @numbers.select { |number| filter.passes? number }
+ end
+
+ def each(&block)
+ @numbers.each do |number|
+ yield number
+ end
+ end
+end
+
+
+class Filter
+ def initialize(&block)
+ @block = block
+ end
+
+ def passes?(number)
+ @block.call(number)
+ end
+
+ def &(other_filter)
+ Filter.new { |number| passes? number and other_filter.passes? number}
+ end
+
+ def |(other_filter)
+ Filter.new { |number| passes? number or other_filter.passes? number}
+ end
+end
+
+class TypeFilter
+ def initialize(type)
+ @type = type
+ end
+
+ def passes?(number)
+ case @type
+ when :integer then number.is_a? Fixnum
+ when :real then number.is_a? Float or number.is_a? Rational
+ when :complex then number.is_a? Complex
+ end
+ end
+
+ def &(other_filter)
+ Filter.new { |number| passes? number and other_filter.passes? number}
+ end
+
+ def |(other_filter)
+ Filter.new { |number| passes? number or other_filter.passes? number}
+ end
+end
+
+class SignFilter
+ def initialize(sign)
+ @sign = sign
+ end
+
+ def passes?(number)
+ case @sign
+ when :positive then number > 0
+ when :negative then number < 0
+ when :non_negative then number >= 0
+ when :non_positive then number <= 0
+ end
+ end
+
+ def &(other_filter)
+ Filter.new { |number| passes? number and other_filter.passes? number}
+ end
+
+ def |(other_filter)
+ Filter.new { |number| passes? number or other_filter.passes? number}
+ end
+end
Веселин обнови решението на 23.10.2014 11:16 (преди около 10 години)
class NumberSet
include Enumerable
def initialize
@numbers = Array.new
end
def <<(number)
- @numbers << number if ! @numbers.include? number
+ @numbers << number unless @numbers.include? number
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def [](filter)
@numbers.select { |number| filter.passes? number }
end
def each(&block)
@numbers.each do |number|
yield number
end
end
end
class Filter
def initialize(&block)
@block = block
end
def passes?(number)
@block.call(number)
end
def &(other_filter)
Filter.new { |number| passes? number and other_filter.passes? number}
end
def |(other_filter)
Filter.new { |number| passes? number or other_filter.passes? number}
end
end
class TypeFilter
def initialize(type)
@type = type
end
def passes?(number)
case @type
when :integer then number.is_a? Fixnum
when :real then number.is_a? Float or number.is_a? Rational
when :complex then number.is_a? Complex
end
end
def &(other_filter)
Filter.new { |number| passes? number and other_filter.passes? number}
end
def |(other_filter)
Filter.new { |number| passes? number or other_filter.passes? number}
end
end
class SignFilter
def initialize(sign)
@sign = sign
end
def passes?(number)
case @sign
when :positive then number > 0
when :negative then number < 0
when :non_negative then number >= 0
when :non_positive then number <= 0
end
end
def &(other_filter)
Filter.new { |number| passes? number and other_filter.passes? number}
end
def |(other_filter)
Filter.new { |number| passes? number or other_filter.passes? number}
end
-end
+end
Много добро решение. Имам няколко много малки забележки:
- Използвай литерали винаги, когато можеш.
[]
винаги е за предпочитане предArray.new
. Конструктура на класа можеш да ползваш, ако му подаваш някакви параметри или блок. -
NumberSet#[]
трябва да връщаNumberSet
обект. В момента връщашArray
обект. - Разгледай как се държи
Array#each
, когато не му подадеш блок. ОчаквамеNumberSet#each
да се държи по същия начин. - Харесва ми, че си помислил за името на
Filter#passes?
. -
Filter#&
,TypeFilter#&
иSignFilter#&
страшно много си приличат. Не мислиш ли, че ти трябва точно един от тях? Същото за|
. - Пробвай да подравниш
then
-овете вcase
-a. Според мен ще постигнеш върховна симетрия. - Няма как да не отбележа, че имаш два празни реда между
NumberSet
иFilter
класовете. Махни единия за да е както другите.
Веселин обнови решението на 23.10.2014 14:46 (преди около 10 години)
class NumberSet
include Enumerable
def initialize
- @numbers = Array.new
+ @numbers = []
end
def <<(number)
@numbers << number unless @numbers.include? number
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def [](filter)
@numbers.select { |number| filter.passes? number }
end
- def each(&block)
- @numbers.each do |number|
- yield number
- end
+ def each
+ return to_enum(:each) unless block_given?
+ @numbers.each { |number| yield number }
end
end
+module FilterModule
+ def &(other_filter)
+ Filter.new { |number| passes? number and other_filter.passes? number}
+ end
+ def |(other_filter)
+ Filter.new { |number| passes? number or other_filter.passes? number}
+ end
+end
+
class Filter
+ include FilterModule
+
def initialize(&block)
@block = block
end
def passes?(number)
@block.call(number)
end
-
- def &(other_filter)
- Filter.new { |number| passes? number and other_filter.passes? number}
- end
-
- def |(other_filter)
- Filter.new { |number| passes? number or other_filter.passes? number}
- end
end
class TypeFilter
+ include FilterModule
+
def initialize(type)
@type = type
end
def passes?(number)
case @type
when :integer then number.is_a? Fixnum
- when :real then number.is_a? Float or number.is_a? Rational
+ when :real then number.is_a? Float or number.is_a? Rational
when :complex then number.is_a? Complex
end
end
-
- def &(other_filter)
- Filter.new { |number| passes? number and other_filter.passes? number}
- end
-
- def |(other_filter)
- Filter.new { |number| passes? number or other_filter.passes? number}
- end
end
class SignFilter
+ include FilterModule
+
def initialize(sign)
@sign = sign
end
def passes?(number)
case @sign
- when :positive then number > 0
- when :negative then number < 0
+ when :positive then number > 0
+ when :negative then number < 0
when :non_negative then number >= 0
when :non_positive then number <= 0
end
- end
-
- def &(other_filter)
- Filter.new { |number| passes? number and other_filter.passes? number}
- end
-
- def |(other_filter)
- Filter.new { |number| passes? number or other_filter.passes? number}
end
end
Успях да го посъкратя малко с модул, но не съм сигурен, че мога да обединя трите филтър класове в един. Предполагам, че ще трябва да използвам alias, обаче проблемът идва оттам, че няма как да побера всички проверки в един метод (заради ограниченията на sceptic).
П.П. Извинявам се за изпуснатия space пред @numbers в each метода :D
- Поправи се за изпуснатия space.
- Този
each
метод може да се реализира по по-прост начин. Той на практика вече е реализиран вArray
. Можеш да делегираш наArray#each
предавайки му блока. - Очакваме
NumberSet#[]
да върнеNumberSet
обект. В момента връщашArray
обект. - Не ти трябва модул. Защо не оставиш
TypeFilter
иSignFilter
да наследятFilter
и по този начин да reuse-нат логиката?
Освен горните коментари мисля, че решението ти е много добро. :)
Веселин обнови решението на 23.10.2014 16:03 (преди около 10 години)
+require 'forwardable'
+
class NumberSet
+ extend Forwardable
include Enumerable
def initialize
@numbers = []
end
def <<(number)
@numbers << number unless @numbers.include? number
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def [](filter)
- @numbers.select { |number| filter.passes? number }
+ reduced_set = NumberSet.new
+ @numbers.select { |number| filter.passes? number }.each do |number|
+ reduced_set << number
+ end
+ reduced_set
end
- def each
- return to_enum(:each) unless block_given?
- @numbers.each { |number| yield number }
- end
+ def_delegator :@numbers, :each
end
-module FilterModule
- def &(other_filter)
- Filter.new { |number| passes? number and other_filter.passes? number}
- end
-
- def |(other_filter)
- Filter.new { |number| passes? number or other_filter.passes? number}
- end
-end
-
class Filter
- include FilterModule
-
def initialize(&block)
@block = block
end
def passes?(number)
@block.call(number)
end
-end
-class TypeFilter
- include FilterModule
+ def &(other_filter)
+ Filter.new { |number| passes? number and other_filter.passes? number}
+ end
+ def |(other_filter)
+ Filter.new { |number| passes? number or other_filter.passes? number}
+ end
+end
+
+class TypeFilter < Filter
def initialize(type)
@type = type
end
def passes?(number)
case @type
when :integer then number.is_a? Fixnum
when :real then number.is_a? Float or number.is_a? Rational
when :complex then number.is_a? Complex
end
end
end
-class SignFilter
- include FilterModule
-
+class SignFilter < Filter
def initialize(sign)
@sign = sign
end
def passes?(number)
case @sign
when :positive then number > 0
when :negative then number < 0
when :non_negative then number >= 0
when :non_positive then number <= 0
end
end
end
Последна итерация на решението :D
Мисля, че се получи доста по-добре от първоначалното :)
Нашата версия на ръководството по стил препоръчва идентиране с едно ниво навътре на when
клаузите на case
. И на мен ми се струва по-четимо с отместване навътре, така че препоръчвам да го промениш по този начин.
Веселин обнови решението на 26.10.2014 19:56 (преди около 10 години)
require 'forwardable'
class NumberSet
extend Forwardable
include Enumerable
def initialize
@numbers = []
end
def <<(number)
@numbers << number unless @numbers.include? number
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def [](filter)
reduced_set = NumberSet.new
@numbers.select { |number| filter.passes? number }.each do |number|
reduced_set << number
end
reduced_set
end
def_delegator :@numbers, :each
end
class Filter
def initialize(&block)
@block = block
end
def passes?(number)
@block.call(number)
end
def &(other_filter)
Filter.new { |number| passes? number and other_filter.passes? number}
end
def |(other_filter)
Filter.new { |number| passes? number or other_filter.passes? number}
end
end
class TypeFilter < Filter
def initialize(type)
@type = type
end
def passes?(number)
case @type
- when :integer then number.is_a? Fixnum
- when :real then number.is_a? Float or number.is_a? Rational
- when :complex then number.is_a? Complex
+ when :integer then number.is_a? Fixnum
+ when :real then number.is_a? Float or number.is_a? Rational
+ when :complex then number.is_a? Complex
end
end
end
class SignFilter < Filter
def initialize(sign)
@sign = sign
end
def passes?(number)
case @sign
- when :positive then number > 0
- when :negative then number < 0
- when :non_negative then number >= 0
- when :non_positive then number <= 0
+ when :positive then number > 0
+ when :negative then number < 0
+ when :non_negative then number >= 0
+ when :non_positive then number <= 0
end
end
end