Втора задача
- Краен срок:
- 27.10.2014 17:00
- Точки:
- 6
Срокът за предаване на решения е отминал
NumberSet
В тази задача искаме от вас да създадете обект, който може да държи в себе си множество числа от различни типове. За целта, ще трябва да напишете клас NumberSet
, който да поддържа следните операции:
Добавяне на число
Добавяне на числа в обект от клас NumberSet
става чрез използване на метода <<
:
numbers = NumberSet.new
numbers << 6
numbers << 7.6
numbers << Rational(22, 7)
numbers << 2.5+3i
Както виждате, един NumberSet
може да съдържа цели числа, числа с плаваща запетая, рационални и комплексни числа. Подробност при добавянето на числа е, че NumberSet
обект трябва да съдържа само уникални елементи. Тоест, можем да добавим число само веднъж в даден NumberSet
:
numbers = NumberSet.new
numbers << 42
numbers << 42
numbers.size #=> 1
За еднакви числа ще считаме и такива от различни типове, но с равна стойност. Например:
-
3
и3.0
се считат за едно и също число -
Rational(22, 2)
и11
се считат за едно и също число -
2.5
и2.5+0i
се считат за едно и също число
Тоест, ако сте добавили числото 42
в множеството, опитът за добавяне на 42
, Rational(84, 2)
, 42+0i
и подобни ще е неуспешен. Те няма да заместят първоначално добавената стойност.
Проверяване на размер
Обектите NumberSet
трябва да предоставят и методи size
и empty?
, които трябва да работят както очаквате, с малкото уточнение за уникалните числа по-горе.
-
size
връща броя на елементите, съдържани отNumberSet
обекта. -
empty?
е предикат, който връщаfalse
, ако има числа вNumberSet
обекта иtrue
в противен случай.
Филтриране
Класът трябва да предоставя и метода []
, който ще има специално значение в контекста на NumberSet
. Този метод приема един аргумент и го използва като филтър, за да селектира елементи от множеството, задоволяващи условието на филтъра и след това връща тези елементи под формата на нов NumberSet
обект.
Има три типа филтри:
-
Filter
- приема блок в конструктора. Блокът от своя страна приема като аргумент число и връщаtrue
илиfalse
, в зависимост от това дали числото задоволява филтъра. Например, този филтър допуска само четни числа:Filter.new { |number| number.even? }
. -
TypeFilter
- приема в конструктора си единствен аргумент, чиято стойност може да бъде:integer
,:real
или:complex
. Ако подаденият аргумент има стойност:integer
, филтърът оставя всички числа от типInteger
. Ако подаденият аргумент има стойност:real
, филтърът оставя всички числа от типFloat
илиRational
. Ако подаденият аргумент има стойност:complex
, филтърът оставя всички числа от типComplex
. -
SignFilter
- приема в конструктора си единствен аргумент, чиято стойност може да бъде:positive
,:non_positive
,:negative
или:non_negative
като съответно филтърът отсява положителни (n > 0), неположителни (n <= 0), отрицателни (n < 0) и неотрицателни числа (n >= 0). Този филтър не е дефиниран за комплексни числа и затова няма да тестваме такива с него.
Филтрите трябва да поддържат два специални оператора - &
и |
.
-
&
е оператор за сечение на два филтъра. Резултатът е трети филтър, който е удовлетворен от число, което удовлетворява и двата филтъра. -
|
е оператор за обединение на два филтъра. Резултатът е трети филтър, който е удовлетворен от число, което удовлетворява поне един от двата филтъра.
Пример за филтриране на числа:
numbers = NumberSet.new
[-3, -2, -1, 0, 1, 2, 3, 4, 5].each do |number|
numbers << number
end
numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even? }].to_a #=> [0, 2, 4]
Ограничения
Ще тестваме NumberSet
само с числа от типовете Fixnum
, Float
, Rational
и Complex
. Няма да подаваме грешни стойности на филтрите.
Enumerable
NumberSet
трябва да имплементира Enumerable
, позволявайки ни да итерираме по числата, които са част от множеството, и да ни дава възможност да използваме всички удобни методи, предоставени от модула.
Това означава, че вашият клас трябва да има в началото си include Enumerable
и да дефинира метод each
, който реализира обхождане.
Примерен тест
Примерния тест може да намерите примерния тест в хранилището с домашните.
Ограничения
Тази задача има следните ограничения:
- Най-много 80 символа на ред
- Най-много 8 реда на метод
- Най-много 2 нива на влагане
- Най-много 4 аргумента на метод
Ако искате да проверите дали задачата ви спазва ограниченията, следвайте инструкциите в описанието на хранилището за домашните.
Няма да приемаме решения, които не спазват ограниченията. Изпълнявайте rubocop
редовно, докато пишете кода. Ако смятате, че rubocop
греши по някакъв начин,
пишете ни на fmi@ruby.bg, заедно с прикачен код или линк към такъв като
private gist. Ако пуснете кода си публично (например във форумите), ще смятаме
това за преписване.