Решение на Втора задача от Елена Орешарова

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

Към профила на Елена Орешарова

Резултати

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

Код

class NumberSet
include Enumerable
def initialize
@numbers = []
end
def each(&block)
@numbers.each &block
end
def <<(number)
unless @numbers.include? number
@numbers << number
end
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def [](filter)
case filter
when Filter then filter.filter_numbers @numbers
when TypeFilter then filter.filter_numbers @numbers
when SignFilter then filter.filter_numbers @numbers
when MixedFilter then filter.filter_numbers @numbers
end
end
end
class Filter
attr_reader :block
def initialize(&block)
if block_given?
@block = block
end
end
def check_number(number)
number if block.call number
end
def filter_numbers(numbers)
result_set = NumberSet.new
numbers.each do |number|
if check_number number then result_set << number end
end
result_set
end
def &(filter)
MixedFilter.new(self, filter, '&')
end
def |(filter)
MixedFilter.new(self, filter, '|')
end
end
class TypeFilter
attr_reader :type
def initialize(type)
@type = type
end
def check_number(number)
case
when ((number.is_a? Integer) && (@type == :integer)) then true
when ((number.is_a? Complex) && (@type == :complex)) then true
when ((number.is_a? Float) && (@type == :real)) then true
when ((number.is_a? Rational) && (@type == :real)) then true
end
end
def filter_numbers(numbers)
result_set = NumberSet.new
numbers.each do |number|
if check_number number then result_set << number end
end
result_set
end
def &(filter)
MixedFilter.new(self, filter, '&')
end
def |(filter)
MixedFilter.new(self, filter, '|')
end
end
class SignFilter
attr_reader :type
def initialize(type)
@type = type
end
def check_number(number)
case @type
when :positive then number if number > 0
when :non_positive then number if number <= 0
when :negative then number if number < 0
when :non_negative then number if number >= 0
end
end
def filter_numbers(numbers)
result_set = NumberSet.new
numbers.each do |number|
if check_number number then result_set << number end
end
result_set
end
def &(filter)
MixedFilter.new(self, filter, '&')
end
def |(filter)
MixedFilter.new(self, filter, '|')
end
end
class MixedFilter
def initialize(first_filter, second_filter, operator)
@first_filter = first_filter
@second_filter = second_filter
@operator = operator
end
def combine_filters(numbers)
first_result = (@first_filter.filter_numbers numbers).to_a
second_result = (@second_filter.filter_numbers numbers).to_a
case @operator
when '&' then (first_result & second_result).uniq
when '|' then (first_result + second_result).uniq
end
end
def filter_numbers(numbers)
result_set = NumberSet.new
combine_filters(numbers).each{ |number| result_set << number}
result_set
end
end

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

..................FFF...

Failures:

  1) NumberSet can combine multiple filters with "and" rule
     Failure/Error: filter        = non_negative & non_zero & mod_3_is_zero
     NoMethodError:
       undefined method `&' for #<MixedFilter:0xb8f11310>
     # /tmp/d20141028-18133-yd8as4/spec.rb:108:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) NumberSet can combine multiple filters with "or" rule
     Failure/Error: filter        = even | negative | more_than_100
     NoMethodError:
       undefined method `|' for #<MixedFilter:0xb8f1062c>
     # /tmp/d20141028-18133-yd8as4/spec.rb:118:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) NumberSet can combine multiple filters with "and" and "or" rules
     Failure/Error: filter        = even & negative | mod_3_is_zero
     NoMethodError:
       undefined method `|' for #<MixedFilter:0xb8fa3a08>
     # /tmp/d20141028-18133-yd8as4/spec.rb:128:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.0219 seconds
24 examples, 3 failures

Failed examples:

rspec /tmp/d20141028-18133-yd8as4/spec.rb:104 # NumberSet can combine multiple filters with "and" rule
rspec /tmp/d20141028-18133-yd8as4/spec.rb:114 # NumberSet can combine multiple filters with "or" rule
rspec /tmp/d20141028-18133-yd8as4/spec.rb:124 # NumberSet can combine multiple filters with "and" and "or" rules

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

Елена обнови решението на 25.10.2014 01:38 (преди около 10 години)

+class NumberSet
+ include Enumerable
+
+ def initialize
+ @numbers = []
+ end
+
+ def each(&block)
+ @numbers.each &block
+ end
+
+ def <<(number)
+ unless @numbers.include? number
+ @numbers << number
+ end
+ end
+
+ def size
+ @numbers.size
+ end
+
+ def empty?
+ @numbers.empty?
+ end
+
+ def [](filter)
+ filter.filter_numbers @numbers
+ end
+end
+
+class Filter
+
+ attr_reader :block
+
+ def initialize(&block)
+ if block_given?
+ @block = block
+ end
+ end
+
+ def filter_numbers(numbers)
+ numbers.select { |number| block.call number }
+ end
+
+ def &(filter)
+ return MixedFilter.new(self, filter, "and")
+ end
+
+ def |(filter)
+ return MixedFilter.new(self, filter, "or")
+ end
+end
+
+class TypeFilter
+
+ attr_reader :type
+
+ def initialize(type)
+ @type = type
+ end
+
+ def filter_numbers(numbers)
+ numbers.select do |number|
+ ((number.is_a? Integer) && (@type == :integer)) ||
+ ((number.is_a? Complex) && (@type == :complex)) ||
+ ((number.is_a? Float) && (@type == :real)) ||
+ ((number.is_a? Rational) && (@type == :real))
+ end
+ end
+
+ def &(filter)
+ return MixedFilter.new(self, filter, "and")
+ end
+
+ def |(filter)
+ return MixedFilter.new(self, filter, "or")
+ end
+
+end
+
+class SignFilter
+
+ attr_reader :type
+
+ def initialize(type)
+ @type = type
+ end
+
+ def filter_numbers(numbers)
+ numbers.select do |number|
+ (number > 0 && (@type == :positive)) ||
+ (number <= 0 && (@type == :non_positive)) ||
+ (number < 0 && (@type == :negative)) ||
+ (number >= 0 && (@type == :non_negative))
+ end
+ end
+
+ def &(filter)
+ return MixedFilter.new(self, filter, "and")
+ end
+
+ def |(filter)
+ return MixedFilter.new(self, filter, "or")
+ end
+
+end
+
+class MixedFilter
+
+ def initialize(first_filter, second_filter, operator)
+ @first_filter = first_filter
+ @second_filter = second_filter
+ @operator = operator
+ end
+
+ def filter_numbers(numbers)
+ first_result = (@first_filter.filter_numbers numbers).to_a
+ second_result = (@second_filter.filter_numbers numbers).to_a
+ case @operator
+ when "and" then return (first_result & second_result).uniq
+ when "or" then return (first_result + second_result).uniq
+ end
+ end
+end

Здрасти,

Мисля си, че във Filter#filter_numbers, TypeFilter#filter_numbers и SignFilter#filter_numbers част от нещата се повтарят. Според мен това numbers.select { |number| ... } можеш да го изнесеш в NumberSet#[]. Също така в момента в NumberSet#[] връщаш Array обект, а ние очакваме NumberSet обратно.

Ако направиш горното, мисля че няма да имаш нужда от MixedFilter обектите. :)

Условията в TypeFilter и SignFilter са твърде сложни. Може би с case нещата ще са по-четими.

Успех. :))

Имаш и някои стилови проблеми, от типа на излишни return ключови думи на редове 46, 50, 99, 103... Редовете 32, 55, 82, 109 пък не трябва да ги има (не трбява да има празен ред там).

Комбинацията на филтри може да стане по-елегантно от подаване на 'and'/'or' низове. Помисли дали няма нещо уникално за Ruby, което може да ти свърши много добра работа :)

Елена обнови решението на 27.10.2014 16:39 (преди около 10 години)

class NumberSet
include Enumerable
def initialize
@numbers = []
end
def each(&block)
@numbers.each &block
end
def <<(number)
unless @numbers.include? number
@numbers << number
end
end
def size
@numbers.size
end
def empty?
@numbers.empty?
end
def [](filter)
- filter.filter_numbers @numbers
+ case filter
+ when Filter then filter.filter_numbers @numbers
+ when TypeFilter then filter.filter_numbers @numbers
+ when SignFilter then filter.filter_numbers @numbers
+ when MixedFilter then filter.filter_numbers @numbers
+ end
end
end
class Filter
-
attr_reader :block
def initialize(&block)
if block_given?
@block = block
end
end
+ def check_number(number)
+ number if block.call number
+ end
+
def filter_numbers(numbers)
- numbers.select { |number| block.call number }
+ result_set = NumberSet.new
+ numbers.each do |number|
+ if check_number number then result_set << number end
+ end
+ result_set
end
def &(filter)
- return MixedFilter.new(self, filter, "and")
+ MixedFilter.new(self, filter, '&')
end
def |(filter)
- return MixedFilter.new(self, filter, "or")
+ MixedFilter.new(self, filter, '|')
end
end
class TypeFilter
-
attr_reader :type
def initialize(type)
@type = type
end
+ def check_number(number)
+ case
+ when ((number.is_a? Integer) && (@type == :integer)) then true
+ when ((number.is_a? Complex) && (@type == :complex)) then true
+ when ((number.is_a? Float) && (@type == :real)) then true
+ when ((number.is_a? Rational) && (@type == :real)) then true
+ end
+ end
+
def filter_numbers(numbers)
- numbers.select do |number|
- ((number.is_a? Integer) && (@type == :integer)) ||
- ((number.is_a? Complex) && (@type == :complex)) ||
- ((number.is_a? Float) && (@type == :real)) ||
- ((number.is_a? Rational) && (@type == :real))
+ result_set = NumberSet.new
+ numbers.each do |number|
+ if check_number number then result_set << number end
end
+ result_set
end
def &(filter)
- return MixedFilter.new(self, filter, "and")
+ MixedFilter.new(self, filter, '&')
end
def |(filter)
- return MixedFilter.new(self, filter, "or")
+ MixedFilter.new(self, filter, '|')
end
end
class SignFilter
-
attr_reader :type
def initialize(type)
@type = type
end
+ def check_number(number)
+ case @type
+ when :positive then number if number > 0
+ when :non_positive then number if number <= 0
+ when :negative then number if number < 0
+ when :non_negative then number if number >= 0
+ end
+ end
+
def filter_numbers(numbers)
- numbers.select do |number|
- (number > 0 && (@type == :positive)) ||
- (number <= 0 && (@type == :non_positive)) ||
- (number < 0 && (@type == :negative)) ||
- (number >= 0 && (@type == :non_negative))
+ result_set = NumberSet.new
+ numbers.each do |number|
+ if check_number number then result_set << number end
end
+ result_set
end
def &(filter)
- return MixedFilter.new(self, filter, "and")
+ MixedFilter.new(self, filter, '&')
end
def |(filter)
- return MixedFilter.new(self, filter, "or")
+ MixedFilter.new(self, filter, '|')
end
end
class MixedFilter
-
def initialize(first_filter, second_filter, operator)
@first_filter = first_filter
@second_filter = second_filter
@operator = operator
end
- def filter_numbers(numbers)
+ def combine_filters(numbers)
first_result = (@first_filter.filter_numbers numbers).to_a
second_result = (@second_filter.filter_numbers numbers).to_a
case @operator
- when "and" then return (first_result & second_result).uniq
- when "or" then return (first_result + second_result).uniq
+ when '&' then (first_result & second_result).uniq
+ when '|' then (first_result + second_result).uniq
end
+ end
+
+ def filter_numbers(numbers)
+ result_set = NumberSet.new
+ combine_filters(numbers).each{ |number| result_set << number}
+ result_set
end
end