# -*- coding: utf-8 -*-
# q1010_answer_2.rb
# 工夫した点・苦労した点・感想等(ご自由にお書きください):
# ・iter_a、iter_b どちらも Enumerator 化して next(および peek)メソッドを利用するようにしました。
# ・loop do〜end を利用することで、StopIteration のことを考えずに済みシンプルなコードになりました♪
# iter_a に存在し、iter_b に出てこない要素(整数)を列挙するメソッド
def enum_diff iter_a, iter_b
return to_enum :enum_diff, iter_a, iter_b unless block_given?
enum_a = iter_a.to_enum
enum_b = iter_b.to_enum
loop do
a = enum_a.peek
b = enum_b.peek
if a < b
yield enum_a.next
elsif a > b
enum_b.next
else
enum_a.next
# enum_b.next
end
end
loop do
yield enum_a.next
end
end
# ※これ以降は変更しないこと。
if $0 == __FILE__
require 'test/unit'
require 'prime'
def primes
Prime.to_enum
end
def nats
(1...Float::INFINITY)
end
def fib
return to_enum :fib unless block_given?
a, b = 0, 1
loop do
yield b
a, b = b, a + b
end
end
class AnswerQ2Test < Test::Unit::TestCase
def test_fib
expected = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
result = enum_diff(fib, []).take(10)
assert_equal(expected, result)
end
def test_nats_without_fib
expected = [4, 6, 7, 9, 10, 11, 12, 14, 15, 16]
result = enum_diff(nats, fib).take(10)
assert_equal(expected, result)
end
def test_fib_without_primes
expected = [1, 1, 8, 21, 34, 55, 144, 377, 610, 987, 2584, 4181, 6765, 10946, 17711, 46368]
result = enum_diff(fib, primes).take_while{|n| n < 50000}
assert_equal(expected, result)
end
def test_fib_reflect
# 3以上20以下の整数を乱択
k = rand(18) + 3
expected = fib.take(k)
result = enum_diff(fib, enum_diff(nats, fib)).take(k)
assert_equal(expected, result)
end
end
end