# -*- coding: utf-8 -*-
# q1038_answer_1.py
# 使用した Python のバージョン:
# ・Python(Python 2.7.3)/Python3(Python 3.2.3)
# 工夫した点・苦労した点・感想等(ご自由にお書きください):
# ・infinite_product_process 関数で得られる generator をキューに登録して順次実行する仕組みにしました。
# ・infinite_product 関数の最初で、引数 iters を IteratorCloner に渡して以降はその結果を利用しています。
# ・infinite_product_process 関数は、今までに列挙した値と、列挙に使わなかった残りの cloners を引数にとって、
# そのうちの先頭の cloner から取得した Iterator(generator)で値を列挙してその値と cloners の残りを yield に引き渡しています。
# 必要に応じてここに import 文を挿入してもOKです(標準添付ライブラリに限る)。
# 例:import itertools
from collections import deque
# 無限リスト(ストリーム)に対応した直積(Cartesian product)を生成して列挙する関数(generator 関数)
def infinite_product(*iters):
"""Cartesian product generator function of (infinite) iterables."""
q = deque([infinite_product_process((), [IteratorCloner(it) for it in iters])])
while q:
it = q.popleft()
try:
vals, next_cloners = next(it)
if not next_cloners:
yield vals
else:
q.append(infinite_product_process(vals, next_cloners))
q.append(it)
except StopIteration:
pass
def infinite_product_process(vals, cloners):
"""Sub-generator function for infinite_product()."""
if not cloners:
yield vals, ()
return
it = cloners[0].get_clone()
xs = cloners[1:]
for e in it:
yield (vals + (e,), xs)
# ここに Lv.2 問題で作成した IteratorCloner クラスを転記してください。
# ※利用せずに解けた場合は、ここには何も記述しないでください。
# ※Lv.2 問題に挑戦していない方は、ここには何も記述せず上記2関数内で完結するようがんばって実装してください。
# v--ココカラ
class IteratorCloner:
def __init__(self, it):
self._it = iter(it)
self._cache = []
def get_clone(self):
index = 0
while True:
if len(self._cache) <= index:
next_val = next(self._it)
self._cache.append(next_val)
yield self._cache[index]
index += 1
# ^--ココマデ
# ※これ以降は変更しないこと。
if __name__ == '__main__':
import unittest
from itertools import count, islice
try:
# for Python2
from itertools import ifilter
except ImportError:
# for Python3
ifilter = filter
def primes():
"""Generator function of Prime numbers."""
g = count(2)
while True:
prime = next(g)
yield prime
g = ifilter(lambda x, prime=prime: x%prime, g)
def nats():
"""Generator function of Integers(>0)."""
return count(1)
def fib():
"""Generator function of Fibonacci numbers."""
a, b = 0, 1
while True:
yield b
a, b = b, a + b
class Q99Test(unittest.TestCase):
"""Test class for infinite_product()."""
def test_fib_only(self):
"""Test for Fibonacci numbers."""
expected = [(1,), (1,), (2,), (3,), (5,), (8,), (13,), (21,), (34,), (55,)]
result = list(islice(infinite_product(fib()), 10))
self.assertEqual(result, expected)
def test_product_nats_fib(self):
"""Test for product of Integers(>0) and Fibonacci numbers."""
expected = [
(1, 1),
(1, 1), (2, 1),
(1, 2), (2, 1), (3, 1),
(1, 3), (2, 2), (3, 1), (4, 1),
(1, 5), (2, 3), (3, 2), (4, 1), (5, 1),
(1, 8), (2, 5), (3, 3), (4, 2), (5, 1), (6, 1)
]
result = list(islice(infinite_product(nats(), fib()), 21))
self.assertEqual(result, expected)
def test_product_primes_nats_fib(self):
"""Test for product of Primes and Integers(>0) and Fibonacci numbers."""
expected = [
(2, 1, 1),
(2, 1, 1), (2, 2, 1),
(3, 1, 1),
(2, 1, 2), (2, 2, 1), (2, 3, 1),
(3, 1, 1), (3, 2, 1),
(5, 1, 1),
(2, 1, 3), (2, 2, 2), (2, 3, 1), (2, 4, 1),
(3, 1, 2), (3, 2, 1), (3, 3, 1),
(5, 1, 1), (5, 2, 1),
(7, 1, 1),
(2, 1, 5), (2, 2, 3), (2, 3, 2), (2, 4, 1), (2, 5, 1),
(3, 1, 3), (3, 2, 2), (3, 3, 1), (3, 4, 1),
(5, 1, 2), (5, 2, 1), (5, 3, 1),
(7, 1, 1), (7, 2, 1),
(11, 1, 1)
]
result = list(islice(infinite_product(primes(), nats(), fib()), 35))
self.assertEqual(result, expected)
def test_product_nats_1_3(self):
"""Test for product of Integers(>0) and [1, 2, 3]."""
expected = [
(1, 1),
(1, 2), (2, 1),
(1, 3), (2, 2), (3, 1),
(2, 3), (3, 2), (4, 1),
(3, 3), (4, 2), (5, 1),
(4, 3), (5, 2), (6, 1)
]
result = list(islice(infinite_product(nats(), range(1, 4)), 15))
self.assertEqual(result, expected)
def test_product_1_3_nats(self):
"""Test for product of [1, 2, 3] and Integers(>0)."""
expected = [
(1, 1),
(1, 2), (2, 1),
(1, 3), (2, 2), (3, 1),
(1, 4), (2, 3), (3, 2),
(1, 5), (2, 4), (3, 3),
(1, 6), (2, 5), (3, 4)
]
result = list(islice(infinite_product(range(1, 4), nats()), 15))
self.assertEqual(result, expected)
def test_product_1_2_x3(self):
"""Test [1, 2] x 3"""
expected = [
(1, 1, 1),
(1, 1, 2), (1, 2, 1), (2, 1, 1),
(1, 2, 2), (2, 1, 2), (2, 2, 1),
(2, 2, 2)
]
# result = list(islice(infinite_product([1, 2], [1, 2], [1, 2]), 8))
result = list(infinite_product([1, 2], [1, 2], [1, 2]))
self.assertEqual(result, expected)
def test_product_1_2_x4(self):
"""Test [1, 2] x 4"""
expected = [
(1, 1, 1, 1),
(1, 1, 1, 2), (1, 1, 2, 1), (1, 2, 1, 1), (2, 1, 1, 1),
(1, 1, 2, 2), (1, 2, 1, 2), (1, 2, 2, 1), (2, 1, 1, 2), (2, 1, 2, 1), (2, 2, 1, 1),
(1, 2, 2, 2), (2, 1, 2, 2), (2, 2, 1, 2), (2, 2, 2, 1),
(2, 2, 2, 2)
]
# result = list(islice(infinite_product([1, 2], [1, 2], [1, 2], [1, 2]), 16))
result = list(infinite_product([1, 2], [1, 2], [1, 2], [1, 2]))
self.assertEqual(result, expected)
# run tests
unittest.main()