Решение на Втора задача от Евгений Бояджиев

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

Към профила на Евгений Бояджиев

Резултати

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

Код

class NumberSet
include Enumerable
:set
def initialize(set = [])
@set = set
end
def each(&block)
@set.each(&block)
end
def <<(number)
if not @set.include? number
@set << number
end
end
def size
@set.size
end
def empty?
@set.empty?
end
def [](filter)
case filter
when Filter, SignFilter, TypeFilter
NumberSet.new @set.select {|number| filter.valid? number}
when Proc
NumberSet.new @set.select {|number| filter.call number}
end
end
end
class Filter
:block
def initialize(&block)
@block = block
end
def &(other)
Filter.new { |number| valid? number and other.valid? number }
end
def |(other)
Filter.new { |number| valid? number or other.valid? number }
end
def valid?(number)
@block.call number
end
end
class TypeFilter
:selector
def initialize(selector)
@selector = selector
end
def &(other)
Filter.new { |number| valid? number and other.valid? number }
end
def |(other)
Filter.new { |number| valid? number or other.valid? number }
end
def valid?(number)
case @selector
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
:selector
def initialize(selector)
@selector = selector
end
def &(other)
Filter.new { |number| valid? number and other.valid? number }
end
def |(other)
Filter.new { |number| valid? number or other.valid? number }
end
def valid?(number)
case @selector
when :positive then 0 < number
when :non_positive then number <= 0
when :negative then number < 0
when :non_negative then 0 <= number
end
end
end

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

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

Finished in 0.02915 seconds
24 examples, 0 failures

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

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

+class NumberSet
+ include Enumerable
+ attr_reader :set
+
+ def initialize set = []
+ @set = set
+ end
+
+ def each &block
+ @set.each do |number|
+ if block_given?
+ block.call number
+ else
+ number
+ end
+ end
+ end
+
+ def << number
+ if number.is_a? Numeric and not include? number
+ @set << number
+ end
+ end
+
+ def include? number
+ contains = false
+ @set.each do |element|
+ if element == number
+ contains = true
+ break
+ end
+ end
+ contains
+ end
+
+ def size
+ @set.size
+ end
+
+ def empty?
+ @set.empty?
+ end
+
+ def [](filter)
+ case filter
+ when Filter then NumberSet.new @set.select {|number| filter.valid? number}
+ when TypeFilter
+ NumberSet.new @set.select {|number| filter.valid? number}
+ when SignFilter
+ NumberSet.new @set.select {|number| filter.valid? number}
+ when Proc then NumberSet.new @set.select {|number| filter.call number}
+ end
+ end
+end
+
+# Filters
+class Filter
+ attr_reader :block
+
+ def initialize &block
+ @block = block
+ end
+
+ def & other
+ Filter.new { |number| (valid? number) & (other.valid? number) }
+ end
+
+ def | other
+ Filter.new { |number| (valid? number) | (other.valid? number) }
+ end
+
+ def valid? number
+ @block.call number
+ end
+end
+
+# TypeFilter options
+# :integer
+# :real
+# :complex
+class TypeFilter
+ attr_reader :selector
+
+ def initialize selector
+ @selector = selector
+ end
+
+ def & other
+ Filter.new { |number| (valid? number) & (other.valid? number) }
+ end
+
+ def | other
+ Filter.new { |number| (valid? number) | (other.valid? number) }
+ end
+
+ def valid? number
+ case @selector
+ when :integer then integer? number
+ when :real then real? number
+ when :complex then complex? number
+ end
+ end
+
+ def integer? number
+ number.class == Fixnum
+ end
+
+ def real? number
+ [Float, Rational].include? number.class
+ end
+
+ def complex? number
+ number.class == Complex
+ end
+end
+
+# SignFilter options
+# :positive
+# :non_positive
+# :negative
+# :non_negative
+class SignFilter
+ attr_reader :selector
+
+ def initialize selector
+ @selector = selector
+ end
+
+ def & other
+ Filter.new { |number| (valid? number) & (other.valid? number) }
+ end
+
+ def | other
+ Filter.new { |number| (valid? number) | (other.valid? number) }
+ end
+
+ def valid? number
+ case @selector
+ when :positive then self.positive? number
+ when :non_positive then self.non_positive? number
+ when :negative then self.negative? number
+ when :non_negative then self.non_negative? number
+ end
+ end
+
+ def positive? number
+ if number > 0 then true else false end
+ end
+
+ def non_positive? number
+ not positive? number
+ end
+
+ def negative? number
+ if number < 0 then true else false end
+ end
+
+ def non_negative? number
+ not negative? number
+ end
+end
  • attr_reader :set е излишно, никой не иска достъп до @set
  • изпускай скоби около дефинициите на методите само когато нямат аргументи
  • бъди консистентен като ползваш case или ползвай само when - then или when нов ред навсякъде, не ги омешвай
  • погледни Enumerable има неща които да ти поспестят код
  • махни коментарите, излишни са
  • няма смисъл да пишеш толкова предикати, проверки от типа на number < 0 са достатъчно ясни за да не се нуждаят от отделен метод

В условието.

  • Най-много 8 реда на метод

  • Най-много 80 символа на ред

В def []

when TypeFilter then NumberSet.new @set.select {|number| filter.valid? number}

и

when SignFilter then NumberSet.new @set.select {|number| filter.valid? number}

Стават повече от 80 символа (поне според Sublime-а). А ако сваля всичко на отделен ред пък ще стане на повече от 8 реда. Мога да съкратя единствено number на n или num, но ми се струва малко по-неясно и неконсистентно. Да не говорим, че вероятно и ще счупи условието на skeptic-a за използването на английските думи.

И затова го направих така. Как да го направя по-умно така че хем да събера всичко на 8 реда, хем 80 символа на ред, хем и хубави имена да има.

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

class NumberSet
include Enumerable
- attr_reader :set
+ :set
- def initialize set = []
+ def initialize (set = [])
@set = set
end
- def each &block
+ def each (&block)
@set.each do |number|
if block_given?
block.call number
else
number
end
end
end
- def << number
+ def << (number)
if number.is_a? Numeric and not include? number
@set << number
end
end
- def include? number
- contains = false
- @set.each do |element|
- if element == number
- contains = true
- break
- end
- end
- contains
- end
-
def size
@set.size
end
def empty?
@set.empty?
end
- def [](filter)
+ def [] (filter)
case filter
when Filter then NumberSet.new @set.select {|number| filter.valid? number}
when TypeFilter
NumberSet.new @set.select {|number| filter.valid? number}
when SignFilter
NumberSet.new @set.select {|number| filter.valid? number}
when Proc then NumberSet.new @set.select {|number| filter.call number}
end
end
end
-# Filters
class Filter
- attr_reader :block
+ :block
- def initialize &block
+ def initialize (&block)
@block = block
end
- def & other
+ def & (other)
Filter.new { |number| (valid? number) & (other.valid? number) }
end
- def | other
+ def | (other)
Filter.new { |number| (valid? number) | (other.valid? number) }
end
- def valid? number
+ def valid? (number)
@block.call number
end
end
-# TypeFilter options
-# :integer
-# :real
-# :complex
+
class TypeFilter
- attr_reader :selector
+ :selector
- def initialize selector
+ def initialize (selector)
@selector = selector
end
- def & other
+ def & (other)
Filter.new { |number| (valid? number) & (other.valid? number) }
end
- def | other
+ def | (other)
Filter.new { |number| (valid? number) | (other.valid? number) }
end
- def valid? number
+ def valid? (number)
case @selector
when :integer then integer? number
when :real then real? number
when :complex then complex? number
end
end
- def integer? number
+ def integer? (number)
number.class == Fixnum
end
- def real? number
+ def real? (number)
[Float, Rational].include? number.class
end
- def complex? number
+ def complex? (number)
number.class == Complex
end
end
-# SignFilter options
-# :positive
-# :non_positive
-# :negative
-# :non_negative
+
class SignFilter
- attr_reader :selector
+ :selector
- def initialize selector
+ def initialize (selector)
@selector = selector
end
- def & other
+ def & (other)
Filter.new { |number| (valid? number) & (other.valid? number) }
end
- def | other
+ def | (other)
Filter.new { |number| (valid? number) | (other.valid? number) }
end
- def valid? number
+ def valid? (number)
case @selector
- when :positive then self.positive? number
- when :non_positive then self.non_positive? number
- when :negative then self.negative? number
- when :non_negative then self.non_negative? number
+ when :positive then 0 < number ? true : false
+ when :non_positive then number <= 0 ? true : false
+ when :negative then number < 0 ? true : false
+ when :non_negative then 0 <= number ? true : false
end
- end
-
- def positive? number
- if number > 0 then true else false end
- end
-
- def non_positive? number
- not positive? number
- end
-
- def negative? number
- if number < 0 then true else false end
- end
-
- def non_negative? number
- not negative? number
end
end

В допълнение на казаното от Марио:

  • number.is_a? Numeric е излишна проверка. Ще подаваме само правилни аргументи.
  • Има и по-добри, по-коректни (и по-кратки) начини да имплементираш NumberSet#each. Потърси варианти.
  • Допълнителна подсказка: сигурен ли си, че имаш нужда да дефинираш метод include?.
  • Текущото ни ръководство по стил изисква да отместваш when с едно ниво навътре спрямо case. Също, по-четимо е, когато в case с кратки when редове, подравниш then клаузите вертикално.
  • За NumberSet#[], три от четирите when-а са с еднакво тяло. Въпреки, че не сме говорили за case, опитай да намериш документация. Има начин да направиш метода само с два when-а.
  • Проверявай дали обект е от даден клас с foo.is_a?(SomeClass).
  • Никога не оставяй интервал преди ( при дефиниция и изивкване на метод (примери са редове 81, 89, 93, 97, и други).
  • Ред 104 не прави нищо и трябва да се изтрие.
  • Скобите на редове 111 и 115 не са поставени правилно. Трябва да са около аргументите, т.е. valid?(number) & other.valid?(number). Освен това, valid? е предикат и връща лъжа/истина. Тук не трябва да използваш побитовото &, а булевият вариант, && (или and).
  • На редове 120-124 няма нужда от тернарен оператор, както и от true/false. Сравненията си връщат лъжа/истина.

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

class NumberSet
include Enumerable
:set
- def initialize (set = [])
+ def initialize(set = [])
@set = set
end
- def each (&block)
- @set.each do |number|
- if block_given?
- block.call number
- else
- number
- end
- end
+ def each(&block)
+ @set.each(&block)
end
- def << (number)
- if number.is_a? Numeric and not include? number
+ def <<(number)
+ if not @set.include? number
@set << number
end
end
def size
@set.size
end
def empty?
@set.empty?
end
- def [] (filter)
+ def [](filter)
case filter
- when Filter then NumberSet.new @set.select {|number| filter.valid? number}
- when TypeFilter
- NumberSet.new @set.select {|number| filter.valid? number}
- when SignFilter
- NumberSet.new @set.select {|number| filter.valid? number}
- when Proc then NumberSet.new @set.select {|number| filter.call number}
+ when Filter, SignFilter, TypeFilter
+ NumberSet.new @set.select {|number| filter.valid? number}
+ when Proc
+ NumberSet.new @set.select {|number| filter.call number}
end
end
end
class Filter
:block
- def initialize (&block)
+ def initialize(&block)
@block = block
end
- def & (other)
- Filter.new { |number| (valid? number) & (other.valid? number) }
+ def &(other)
+ Filter.new { |number| valid? number and other.valid? number }
end
- def | (other)
- Filter.new { |number| (valid? number) | (other.valid? number) }
+ def |(other)
+ Filter.new { |number| valid? number or other.valid? number }
end
- def valid? (number)
+ def valid?(number)
@block.call number
end
end
class TypeFilter
:selector
- def initialize (selector)
+ def initialize(selector)
@selector = selector
end
- def & (other)
- Filter.new { |number| (valid? number) & (other.valid? number) }
+ def &(other)
+ Filter.new { |number| valid? number and other.valid? number }
end
- def | (other)
- Filter.new { |number| (valid? number) | (other.valid? number) }
+ def |(other)
+ Filter.new { |number| valid? number or other.valid? number }
end
- def valid? (number)
+ def valid?(number)
case @selector
- when :integer then integer? number
- when :real then real? number
- when :complex then complex? number
+ 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 integer? (number)
- number.class == Fixnum
- end
-
- def real? (number)
- [Float, Rational].include? number.class
- end
-
- def complex? (number)
- number.class == Complex
- end
end
class SignFilter
:selector
- def initialize (selector)
+ def initialize(selector)
@selector = selector
end
- def & (other)
- Filter.new { |number| (valid? number) & (other.valid? number) }
+ def &(other)
+ Filter.new { |number| valid? number and other.valid? number }
end
- def | (other)
- Filter.new { |number| (valid? number) | (other.valid? number) }
+ def |(other)
+ Filter.new { |number| valid? number or other.valid? number }
end
- def valid? (number)
+ def valid?(number)
case @selector
- when :positive then 0 < number ? true : false
- when :non_positive then number <= 0 ? true : false
- when :negative then number < 0 ? true : false
- when :non_negative then 0 <= number ? true : false
+ when :positive then 0 < number
+ when :non_positive then number <= 0
+ when :negative then number < 0
+ when :non_negative then 0 <= number
end
end
end