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

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

Към профила на Диана Генева

Резултати

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

Код

class NumberSet
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 each(&block)
@numbers.each(&block)
end
def [](filter)
filtered = NumberSet.new
@numbers.each do |number|
filtered << number if filter.condition.call(number)
end
filtered
end
end
class Filter
attr_reader :condition
def initialize(&condition)
@condition = condition
end
def &(other)
Filter.new { |x| condition.call(x) and other.condition.call(x) }
end
def |(other)
Filter.new { |x| condition.call(x) or other.condition.call(x) }
end
end
class TypeFilter < Filter
attr_reader :condition
def initialize(type)
case type
when :integer then super() { |x| x.is_a? Integer }
when :real then super() { |x| x.is_a? Float or x.is_a? Rational }
when :complex then super() { |x| x.is_a? Complex }
end
end
end
class SignFilter < Filter
attr_reader :condition
def initialize(sign)
case sign
when :positive then super() { |x| x > 0 }
when :non_positive then super() { |x| x <= 0 }
when :non_negative then super() { |x| x >= 0 }
when :negative then super() { |x| x < 0 }
end
end
end

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

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

Finished in 0.02232 seconds
24 examples, 0 failures

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

Диана обнови решението на 23.10.2014 00:40 (преди над 9 години)

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

Диана обнови решението на 23.10.2014 00:44 (преди над 9 години)

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

Като цяло много хубаво решение, браво! Само няколко неща:

  • Имаш леки проблеми със space-овете. По конвенция трябва да оставяш едно празно място преди и след отварящата { и още едно преди затварящата } когато става дума за блокове. Също не оставяй празни места между името на метод и скобите с аргументите или & и името на block-a, който получаваш, както си направила в конструктора на Filter.
  • Даваш повече знание и свобода за манипулация над твоите обекти, отколкото е нужно. Това нарушава Law of Dementer, който е един от градивните принципи за добър ООП дизайн. В момента няма нещо, което да има нужда от attr_accessor :number_set, съответно би следвало NumberSet да се опитва да си го крие. (: Това важи и за филтрите. Filter#condition се извиква в NumberSet, но никъде извън дефиницията на самите филтри не се променя. Следователно би било по-добре да използваш attr_reader, а не attr_accessor. Дори и така ще бъде малко спорно - външните класове трябва да знаят, че condition е някакъв proc и да му викат call. Дали няма да е по-приятно, ако има по един предикат във филтрите, който скрива този имплементационен детайл?
  • if not е причината unless да съществува. Условието и действията са достатъчно кратки, за да можеш да ги запишеш на един ред - x unless y.
  • Това не е напълно вярна имплементация на each. Hint: виж какво би станало, ако го извикаш без блок. Дори и да го оправиш, няма нужда да преоткриваш колелото - можеш да го вземеш с име в NumberSet#each и после да прехвърлиш работата на Array#each.
  • Предпочитай наследяване пред mixin-ване в общия случай. Можеше & и | да ги дефинираш във Filter и да го наследиш от другите два. Тогава ще имаш и опцията да употребиш super като директно подаваш block, без да трябва да минаваш през lambda-и.
  • Старай се именуването ти да е консистентно. number, n и x имат едно и също значение, но са три. Лично на мен ми харесва най-много number. Също result е доста общо. Опитай се да измислиш нещо по-говоримо.
  • Кодът става по-красив, ако подравняваш някои конструкции, когато се срещат на съседни редове. Сред тях са =, then и стойностите на hash-овете.
  • Слагай един празен ред между методите и клас макросите (include, attr_accessor и т.н.), за по-добра четимост.

Голяма част от горните точки са по-скоро дребни неща. Не се притеснявай, справила си се похвално още от първата версия. (:

Диана обнови решението на 23.10.2014 21:33 (преди над 9 години)

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

Браво :)

На мен малко ми бърка в здравето това: @set = []. Звучи ми като string = 42. От друга страна, вграденият клас Set не помага много, понеже той би приел 5 и 5.0 като различни елементи. Може би бих потърсил друго име за променливата, но, честно казано, нямам качествено по-добри идеи. Повечето хора използват @numbers или @set.

Диана и Никола, ако ви дойде по-добра идея, споделете. Ако не, просто игнорирайте бележката.

Ох, да си призная честно го смених от numbers на set само защото не можех да мина скептик за символи на ред. Реших, че е по-належащо да прекръсря result и n ( който беше n поради същите причини) Като го върна на numbers пак става 83... и вече ме дразни. Изглежда все едно съм си кръстила кучето Куче...май по-скоро все едно съм си кръстила кучето Котка... :/

Диана обнови решението на 27.10.2014 13:11 (преди над 9 години)

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