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

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

Към профила на Мартина Радева

Резултати

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

Код

class NumberSet
include Enumerable
def initialize
@number_set = []
end
def empty?
! @number_set.any?
end
def each(&block)
@number_set.each(&block)
end
def size
@number_set.count
end
def <<(number)
@number_set << number unless @number_set.include?(number)
self
end
def [](filter)
filtered_set = NumberSet.new
self.each {|current| filtered_set << current if filter.accepts?(current)}
filtered_set
end
# def &(argument)
# self and argument
# end
# def |(argument)
# self or argument
# end
end
class Filter
def initialize (&block)
@filter = block
end
def accepts?(number)
return true if @filter.call(number)
end
end
class TypeFilter
def initialize (data_type)
@data_type = data_type
end
def accepts?(number)
case @data_type
when :integer then Filter.new {|n| n.is_a? Integer}.accepts?(number)
when :complex then Filter.new {|n| n.is_a? Complex}.accepts?(number)
when :real then Filter
.new {|n| n.is_a? Float or n.is_a? Rational}.accepts?(number)
end
end
end
class SignFilter
def initialize (data_type)
@data_type = data_type
end
def accepts?(sign)
case @data_type
when :positive then Filter.new {|n| n > 0}.accepts?(sign)
when :non_positive then Filter.new {|n| n <= 0}.accepts?(sign)
when :negative then Filter.new {|n| n < 0}.accepts?(sign)
when :non_negative then Filter.new {|n| n >= 0}.accepts?(sign)
end
end
end

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

................FFFFFF..

Failures:

  1) NumberSet can combine two filters with "and" rule
     Failure/Error: filter = SignFilter.new(:non_negative) & Filter.new { |number| number != 0 }
     NoMethodError:
       undefined method `&' for #<SignFilter:0xb8b91cf8 @data_type=:non_negative>
     # /tmp/d20141028-18133-jkvms4/spec.rb:91: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 two filters with "or" rule
     Failure/Error: filter = Filter.new { |number| number % 2 == 0 } | Filter.new { |number| number > 5 }
     NoMethodError:
       undefined method `|' for #<Filter:0xb8b91000>
     # /tmp/d20141028-18133-jkvms4/spec.rb:98: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" rule
     Failure/Error: filter        = non_negative & non_zero & mod_3_is_zero
     NoMethodError:
       undefined method `&' for #<SignFilter:0xb8b90434 @data_type=:non_negative>
     # /tmp/d20141028-18133-jkvms4/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)>'

  4) NumberSet can combine multiple filters with "or" rule
     Failure/Error: filter        = even | negative | more_than_100
     NoMethodError:
       undefined method `|' for #<Filter:0xb8bf3a98 @filter=#<Proc:0xb8bf3ad4>>
     # /tmp/d20141028-18133-jkvms4/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)>'

  5) NumberSet can combine multiple filters with "and" and "or" rules
     Failure/Error: filter        = even & negative | mod_3_is_zero
     NoMethodError:
       undefined method `&' for #<Filter:0xb8bf2f80 @filter=#<Proc:0xb8bf3ad4>>
     # /tmp/d20141028-18133-jkvms4/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)>'

  6) NumberSet can combine multiple filters with "and", "or" and parenthesis
     Failure/Error: filter        = even & (negative | mod_3_is_zero)
     NoMethodError:
       undefined method `|' for #<SignFilter:0xb8bf247c @data_type=:negative>
     # /tmp/d20141028-18133-jkvms4/spec.rb:138: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.0212 seconds
24 examples, 6 failures

Failed examples:

rspec /tmp/d20141028-18133-jkvms4/spec.rb:90 # NumberSet can combine two filters with "and" rule
rspec /tmp/d20141028-18133-jkvms4/spec.rb:97 # NumberSet can combine two filters with "or" rule
rspec /tmp/d20141028-18133-jkvms4/spec.rb:104 # NumberSet can combine multiple filters with "and" rule
rspec /tmp/d20141028-18133-jkvms4/spec.rb:114 # NumberSet can combine multiple filters with "or" rule
rspec /tmp/d20141028-18133-jkvms4/spec.rb:124 # NumberSet can combine multiple filters with "and" and "or" rules
rspec /tmp/d20141028-18133-jkvms4/spec.rb:134 # NumberSet can combine multiple filters with "and", "or" and parenthesis

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

Мартина обнови решението на 26.10.2014 00:57 (преди над 9 години)

+class NumberSet
+include Enumerable
+
+ def initialize
+ @number_set = []
+ end
+
+ def empty?
+ ! @number_set.any?
+ end
+
+ def each(&block)
+ @number_set.each(&block)
+ end
+
+ def size
+ @number_set.count
+ end
+
+ def <<(number)
+ @number_set << number unless @number_set.include?(number)
+ end
+
+end
+# any idea why line 21 doesn't work?

Ред 21. Гледам го. Трябва да работи. Очаквам да работи. Не работи. Ще се радвам на коментар или насока по въпроса.

Сега на втори поглед го гледам и това с unless не ми изглежда ок, не работи и с ? накрая, нито с класически if .. then .. end . Със сигурност ми е пред очите, но не го виждам.

Тестовете са ми в Github.

От тестовете, които не си коментирала виждам проблем на 33 ред set.incl(2). Нямаш incl метод в NumberSet.

Също така, за да можеш да правиш така numbers << 1 << 2 << 3, NumberSet#<< метода ти трябва да връща self. Това ще позволи такова chain-ване на извиквания на <<.

expect(NumberSet.new<<1).to eq [1] не е ясно колко коректен тест е тъй като резултатът от NumberSet#<< може да не е Array. По скоро бих го тествал с include от колкото с eq.

Да, това е останало от дебъг. Пушнах актуална версия на теста. Методът не работи и така

  def <<(number)
    if !(@number_set.include?(number)) then @number_set << number end
  end

EDIT: куул, това с чейнването не го знаех. Ще пробвам тъй. Благодаря!

EDIT 2: Стана. Много благодаря!

Мартина обнови решението на 27.10.2014 00:33 (преди над 9 години)

class NumberSet
include Enumerable
def initialize
@number_set = []
end
def empty?
! @number_set.any?
end
def each(&block)
@number_set.each(&block)
end
def size
@number_set.count
end
def <<(number)
- @number_set << number unless @number_set.include?(number)
+ @number_set << number unless @number_set.include?(number)
+ self
end
+ def [](&filter)
+ filtered_set = NumberSet.new
+ self.each {|current| filtered_set << current if filter.call(current)}
+ filtered_set
+ end
+
+ # def &(argument)
+ # self and argument
+ # end
+
+ # def |(argument)
+ # self or argument
+ # end
end
-# any idea why line 21 doesn't work?
+
+class Filter
+ def initialize
+ #i want to assign
+ end
+end
+
+class TypeFilter
+ def initialize(data_type)
+ case data_type
+ when :integer then @filter = -> (n) {n.class = Integer}
+ when :complex then @filter = -> (n) {n.class = Complex}
+ when :real then @filter = -> (n) {n.class = Float or n.class = Rational}
+ end
+ end
+end
+
+class SignFilter
+ def initialize(sign)
+ case sign
+ when :positive then @filter = -> (n) {n > 0}
+ when :non_positive then @filter = -> (n) {n <= 0}
+ when :negative then @filter = -> (n) {n < 0}
+ when :non_negative then @filter = -> (n) {n >= 0}
+ end
+end
+
+end

Все още е work in progress. Не знам доколко е ок да задавам въпрос в коментар към недовършено решение - но ще опитам. Имам чувството, че копая в съвсем грешна посока.

Опитвам се да направя следното:

Вариант 1:

Всички филтри при инициализирането си връщат съответна анонимна функция, която [] да ползва като критерий за филтриране. Операторите & и | се предефинират, но като цяло [] работи с обединение /сечение на два блока като аргумент.

В този вариант не ми е ясно как да взема блока, с който е извикан Filter.new {this_block} и да го върна като резултат на initialize. С yield мога да изпълня блока, block_given? дава дали го има, но самият той има ли как да се вземе като функция/lambda, block/ от вътре в метода initialize ?

Вариант 2:

class Filter
  def initialize
    filtered_set = NumberSet.new
    @number_set.each {|current| filtered_set << current if yield current}
    filtered_set
  end
end

За това не ми е ясно как ще взема @number_set, която не е в същия клас.

Някаква насока – разбира се, колкото прецените, че е честно : ) ?

Опитът ти е успешен.

Вариант едно отпада. Без значение какво връщаш от initialize, не забравяй, че той се вика от метода new, който винаги връща нов обект - инстанция на класа, за който е извикан. Кодът за new в интерпретатора е нещо от сорта на:

VALUE method_call_new(VALUE klass, int argc, VALUE *args) {
    VALUE object = create_new_object(klass);
    invoke_initialize(object, argc, args);
    return object
}

Като изключим жалкия ми опит да пиша C, искам да се фокусираш върху invoke_initialize извикването. Това е твоя initialize метод. Това, което искам да илюстрирам е, че резултатът, който той връща се игнорира и new връща новосъздадения обект. Това прави ли смисъл?

Скачаме на вариант две. Filter#initialize трябва да приема блок. Кодът, който ти си написала е по-скоро имплементацията на NumberSet#[]. Там трябва да стои създаването на нов NumberSet и пълненето му с елементи на базата на филтъра. Филтрите трябва да могат да кажат за едно число - минава ли филтъра, или не. Толкова. :)

Мартина обнови решението на 27.10.2014 08:42 (преди над 9 години)

class NumberSet
include Enumerable
def initialize
@number_set = []
end
def empty?
! @number_set.any?
end
def each(&block)
@number_set.each(&block)
end
def size
@number_set.count
end
def <<(number)
@number_set << number unless @number_set.include?(number)
self
end
- def [](&filter)
+ def [](filter)
filtered_set = NumberSet.new
self.each {|current| filtered_set << current if filter.call(current)}
filtered_set
end
# def &(argument)
# self and argument
# end
# def |(argument)
# self or argument
# end
end
class Filter
- def initialize
- #i want to assign
+ def initialize (number)
+ return true if yield number
end
end
class TypeFilter
def initialize(data_type)
case data_type
- when :integer then @filter = -> (n) {n.class = Integer}
- when :complex then @filter = -> (n) {n.class = Complex}
- when :real then @filter = -> (n) {n.class = Float or n.class = Rational}
- end
+ when :integer then Filter.new {|n| n.class = Integer}
+ when :complex then Filter.new {|n| n.class = Complex}
+ when :real then Filter.new {|n| n.class = Float or n.class = Rational}
end
end
class SignFilter
def initialize(sign)
case sign
- when :positive then @filter = -> (n) {n > 0}
- when :non_positive then @filter = -> (n) {n <= 0}
- when :negative then @filter = -> (n) {n < 0}
- when :non_negative then @filter = -> (n) {n >= 0}
+ when :positive then Filter.new {|n| n > 0}
+ when :non_positive then Filter.new {|n| n <= 0}
+ when :negative then Filter.new {|n| n < 0}
+ when :non_negative then Filter.new {|n| n >= 0}
+ end
end
end
end

Благодаря за бързия коментар.

Тъй като това е първото парче С, което виждам в живота си, няма нужда да го окачествяваш като жалък опит :D. Моля, не стреляй по пианиста.

На четвъртия път, в който ти прочетох коментара, разбрах горе-долу какво трябва да прави филтъра. Със сигурност не се пише така – основно понеже нищо от написаното не работи.

Ако мога да вметна въпрос

„Филтрите трябва да могат да кажат за едно число - минава ли филтъра, или не. Толкова. :) ”

Това число като аргумент ли трябва да им се зададе? Защото извикването им със синтаксиса от условието numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even? }] не мога да си представя как точно ще си го вземе.

Чувствам се длъжна да кача последната (неработеща) версия на задачата, преди да отида на работа и дедлайна да се хлопне.

В момента се опитваш да връщаш резултат от initialize. Направи си един метод във филтъра, който се казва accepts?(number) / satisfied_by?(number) / met_by?(number). Този метод ще ни казва дали number удовлетворява филтъра. Съответно в NumberSet#[] ще разчиташ на този метод вместо на call. :)

Мартина обнови решението на 27.10.2014 16:31 (преди над 9 години)

class NumberSet
include Enumerable
def initialize
@number_set = []
end
def empty?
! @number_set.any?
end
def each(&block)
@number_set.each(&block)
end
def size
@number_set.count
end
def <<(number)
@number_set << number unless @number_set.include?(number)
self
end
def [](filter)
filtered_set = NumberSet.new
- self.each {|current| filtered_set << current if filter.call(current)}
+ self.each {|current| filtered_set << current if filter.accepts?(current)}
filtered_set
end
# def &(argument)
# self and argument
# end
# def |(argument)
# self or argument
# end
end
class Filter
- def initialize (number)
- return true if yield number
+ def initialize (&block)
+ @filter = block
end
+
+ def accepts?(number)
+ return true if @filter.call(number)
+ end
end
class TypeFilter
- def initialize(data_type)
- case data_type
- when :integer then Filter.new {|n| n.class = Integer}
- when :complex then Filter.new {|n| n.class = Complex}
- when :real then Filter.new {|n| n.class = Float or n.class = Rational}
+ def initialize (data_type)
+ @data_type = data_type
end
+
+ def accepts?(number)
+ case @data_type
+ when :integer then Filter.new {|n| n.is_a? Integer}.accepts?(number)
+ when :complex then Filter.new {|n| n.is_a? Complex}.accepts?(number)
+ when :real then Filter
+ .new {|n| n.is_a? Float or n.is_a? Rational}.accepts?(number)
+ end
+ end
end
class SignFilter
- def initialize(sign)
- case sign
- when :positive then Filter.new {|n| n > 0}
- when :non_positive then Filter.new {|n| n <= 0}
- when :negative then Filter.new {|n| n < 0}
- when :non_negative then Filter.new {|n| n >= 0}
+ def initialize (data_type)
+ @data_type = data_type
+ end
+
+ def accepts?(sign)
+ case @data_type
+ when :positive then Filter.new {|n| n > 0}.accepts?(sign)
+ when :non_positive then Filter.new {|n| n <= 0}.accepts?(sign)
+ when :negative then Filter.new {|n| n < 0}.accepts?(sign)
+ when :non_negative then Filter.new {|n| n >= 0}.accepts?(sign)
end
end
end
-
-end