Решение на Втора задача от Ангел Ангелов

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

Към профила на Ангел Ангелов

Резултати

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

Код

class NumberSet < Array
def <<(number)
super << number unless include? number
end
def [](filter)
each_with_object(NumberSet.new) do |number, filtered_set|
filtered_set << number if filter.matches?(number)
end
end
end
class Filter
def &(other)
Filter.new { |number| matches?(number) and other.matches?(number) }
end
def |(other)
Filter.new { |number| matches?(number) or other.matches?(number) }
end
def initialize(&condition)
@condition = condition
end
def matches?(number)
@condition.call(number)
end
end
class SignFilter < Filter
def initialize(sign)
@sign = sign
end
def matches?(number)
case @sign
when :positive then number > 0
when :non_positive then number <= 0
when :negative then number < 0
when :non_negative then number >= 0
end
end
end
class TypeFilter < Filter
def initialize(type)
@type = type
end
def matches?(number)
case @type
when :integer then number.is_a? Integer
when :real then number.is_a? Float or number.is_a? Rational
when :complex then number.is_a? Complex
end
end
end

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

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

Finished in 0.02225 seconds
24 examples, 0 failures

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

Ангел обнови решението на 23.10.2014 00:34 (преди около 10 години)

+class NumberSet
+ include Enumerable
+
+ def initialize()
+ @set = []
+ end
+
+ def <<(element)
+ @set << element if not @set.include? element
+ end
+
+ def size()
+ @set.size
+ end
+
+ def empty?()
+ @set.empty?
+ end
+
+ def each()
+ @set.each { |element| yield element }
+ end
+
+ def [](filter)
+ result = NumberSet.new
+ each { |element| result << element if filter.test(element) }
+ result
+ end
+end
+
+module SetFilter
+ def &(other)
+ Filter.new { |element| test(element) and other.test(element) }
+ end
+
+ def |(other)
+ Filter.new { |element| test(element) or other.test(element) }
+ end
+end
+
+class Filter
+ include SetFilter
+
+ def initialize(&condition)
+ @condition = condition
+ end
+
+ def test(element)
+ @condition.call(element)
+ end
+end
+
+class SignFilter
+ include SetFilter
+
+ def initialize(sign)
+ @sign = sign
+ end
+
+ def test(element)
+ case @sign
+ when :positive then element > 0
+ when :non_positive then element <= 0
+ when :negative then element < 0
+ when :non_negative then element >= 0
+ end
+ end
+end
+
+class TypeFilter
+ include SetFilter
+
+ def initialize(type)
+ @type = type
+ end
+
+ def test(element)
+ case @type
+ when :integer then element.is_a? Integer
+ when :real then element.is_a? Float or element.is_a? Rational
+ when :complex then element.is_a? Complex
+ end
+ end
+end

Браво, почти си го заковал още от първата версия! Само няколко забележки:

  • Изпускай скобите при дефинирането и викането на методи без параметри.
  • Никога if not! Има причина unless да съществува. (:
  • Това не е напълно вярна имплементация на each. Hint: виж какво би станало, ако го извикаш без блок. Дори и да го оправиш, няма нужда да преоткриваш колелото - можеш да вземеш блока с име в NumberSet#each и да го предадеш на Array#each.
  • Предпочитай наследяване пред mixin-ване в общия случай. Можеше & и | да ги дефинираш във Filter и да го наследиш от другите два филтъра.
  • Има място за подобрение на имената. test е предикат, би следвало да завършва на ?. Но пак - "тествам множеството с филтъра" не звучи перфектно. NumberSet може да се имплементира с множество, но съдържа числа. Същото важи и за елементите му. result е едно от най-generic имената ever. В 99% от случаите има нещо по-конкретно, което да изразява семантиката в дадената ситуация.

Ангел обнови решението на 23.10.2014 20:14 (преди около 10 години)

class NumberSet
include Enumerable
- def initialize()
+ def initialize
@set = []
end
- def <<(element)
- @set << element if not @set.include? element
+ def <<(number)
+ @set << number unless @set.include? number
end
- def size()
+ def size
@set.size
end
- def empty?()
+ def empty?
@set.empty?
end
- def each()
- @set.each { |element| yield element }
+ def each(&block)
+ @set.each(&block)
end
def [](filter)
- result = NumberSet.new
- each { |element| result << element if filter.test(element) }
- result
+ filtered_set = NumberSet.new
+ each { |number| filtered_set << number if filter.matches?(number) }
+ filtered_set
end
end
-module SetFilter
+class Filter
def &(other)
- Filter.new { |element| test(element) and other.test(element) }
+ Filter.new { |number| matches?(number) and other.matches?(number) }
end
def |(other)
- Filter.new { |element| test(element) or other.test(element) }
+ Filter.new { |number| matches?(number) or other.matches?(number) }
end
-end
-class Filter
- include SetFilter
-
def initialize(&condition)
@condition = condition
end
- def test(element)
- @condition.call(element)
+ def matches?(number)
+ @condition.call(number)
end
end
-class SignFilter
- include SetFilter
-
+class SignFilter < Filter
def initialize(sign)
@sign = sign
end
- def test(element)
+ def matches?(number)
case @sign
- when :positive then element > 0
- when :non_positive then element <= 0
- when :negative then element < 0
- when :non_negative then element >= 0
+ when :positive then number > 0
+ when :non_positive then number <= 0
+ when :negative then number < 0
+ when :non_negative then number >= 0
end
end
end
-class TypeFilter
- include SetFilter
-
+class TypeFilter < Filter
def initialize(type)
@type = type
end
- def test(element)
+ def matches?(number)
case @type
- when :integer then element.is_a? Integer
- when :real then element.is_a? Float or element.is_a? Rational
- when :complex then element.is_a? Complex
+ when :integer then number.is_a? Integer
+ when :real then number.is_a? Float or number.is_a? Rational
+ when :complex then number.is_a? Complex
end
end
end

Ангел обнови решението на 23.10.2014 22:17 (преди около 10 години)

-class NumberSet
+class NumberSet < Array
include Enumerable
- def initialize
- @set = []
- end
-
def <<(number)
- @set << number unless @set.include? number
- end
-
- def size
- @set.size
- end
-
- def empty?
- @set.empty?
- end
-
- def each(&block)
- @set.each(&block)
+ super << number unless include? number
end
def [](filter)
filtered_set = NumberSet.new
each { |number| filtered_set << number if filter.matches?(number) }
filtered_set
end
end
class Filter
def &(other)
Filter.new { |number| matches?(number) and other.matches?(number) }
end
def |(other)
Filter.new { |number| matches?(number) or other.matches?(number) }
end
def initialize(&condition)
@condition = condition
end
def matches?(number)
@condition.call(number)
end
end
class SignFilter < Filter
def initialize(sign)
@sign = sign
end
def matches?(number)
case @sign
when :positive then number > 0
when :non_positive then number <= 0
when :negative then number < 0
when :non_negative then number >= 0
end
end
end
class TypeFilter < Filter
def initialize(type)
@type = type
end
def matches?(number)
case @type
when :integer then number.is_a? Integer
when :real then number.is_a? Float or number.is_a? Rational
when :complex then number.is_a? Complex
end
end
end
  • Не съм убеден доколко ми харесва идеята, че си наследил от Array. Ако настояваш да го оставиш така, не мисля, че има много смисъл от include Enumerable.

  • За NumberSet#[] ако искаш можеш да погледнеш Enumerable#each_with_object.

Иначе всичко друго си е spot on!

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

class NumberSet < Array
- include Enumerable
-
def <<(number)
super << number unless include? number
end
def [](filter)
- filtered_set = NumberSet.new
- each { |number| filtered_set << number if filter.matches?(number) }
- filtered_set
+ each_with_object(NumberSet.new) do |number, filtered_set|
+ filtered_set << number if filter.matches?(number)
+ end
end
end
class Filter
def &(other)
Filter.new { |number| matches?(number) and other.matches?(number) }
end
def |(other)
Filter.new { |number| matches?(number) or other.matches?(number) }
end
def initialize(&condition)
@condition = condition
end
def matches?(number)
@condition.call(number)
end
end
class SignFilter < Filter
def initialize(sign)
@sign = sign
end
def matches?(number)
case @sign
when :positive then number > 0
when :non_positive then number <= 0
when :negative then number < 0
when :non_negative then number >= 0
end
end
end
class TypeFilter < Filter
def initialize(type)
@type = type
end
def matches?(number)
case @type
when :integer then number.is_a? Integer
when :real then number.is_a? Float or number.is_a? Rational
when :complex then number.is_a? Complex
end
end
end

Ангел обнови решението на 27.10.2014 11:01 (преди около 10 години)

class NumberSet < Array
def <<(number)
super << number unless include? number
end
def [](filter)
each_with_object(NumberSet.new) do |number, filtered_set|
- filtered_set << number if filter.matches?(number)
+ filtered_set << number if filter.matches?(number)
end
end
end
class Filter
def &(other)
Filter.new { |number| matches?(number) and other.matches?(number) }
end
def |(other)
Filter.new { |number| matches?(number) or other.matches?(number) }
end
def initialize(&condition)
@condition = condition
end
def matches?(number)
@condition.call(number)
end
end
class SignFilter < Filter
def initialize(sign)
@sign = sign
end
def matches?(number)
case @sign
when :positive then number > 0
when :non_positive then number <= 0
when :negative then number < 0
when :non_negative then number >= 0
end
end
end
class TypeFilter < Filter
def initialize(type)
@type = type
end
def matches?(number)
case @type
when :integer then number.is_a? Integer
when :real then number.is_a? Float or number.is_a? Rational
when :complex then number.is_a? Complex
end
end
end