2015/06/15

Python筆記:itertools.chain

練習使用標準模組itertools裡的chain,可以把數個可迭代者串連起來。

使用3.x版的函式print
from __future__ import print_function
匯入
from itertools import chain

手上有三個串列
a = [70, 81, 92]
b = ['hi', 'hello', 'aloha', 'ahoy']
c = [31.3, 32.5, 29.2, 28.5]

按照想要的順序,丟入chain,得到迭代器,
for e in chain(a, b, c):
    print(e, ' ', end='')

輸出:70  81  92  hi  hello  aloha  ahoy  31.3  32.5  29.2  28.5

自己實作
def my_chain(*iterables):
    for it in iterables:
        for e in it:
            yield e

for e in my_chain(a, b, c):
    print(e, ' ', end='')

輸出:同上

另外,如果你想丟進去的東西,會是動態產生、或是某種迭代器,那麼可使用chain.from_iterable。

底下這個函式,若傳入4,會依序回傳[0]、[0, 1]、[0, 1, 2]、[0, 1, 2, 3](不一定是串列,依Python版本而定)
def foo(x):
    i = 1
    while i <= x:
        yield range(0, i)
        i += 1

使用chain.from_iterable把它們串起來
for e in chain.from_iterable(foo(4)):
    print(e, ' ', end='')

輸出:0  0  1  0  1  2  0  1  2  3

自己實作
def my_chain_from_iterable(iterables):
    for it in iterables:
        for e in it:
            yield e

for e in my_chain_from_iterable(foo(4)):
    print(e, ' ', end='')

輸出:同上

3 comments:

  1. 請問版主一下,我使用Python 3.6,去run您文章中的

    def foo(x):
    i = 1
    while i <= x:
    yield range(0, i)
    i += 1
    用for i in foo(4): print(i),去iterate後得到的是
    range(0, 1)
    range(0, 2)
    range(0, 3)
    range(0, 4)
    除非把程式碼改成
    def foo(x):
    i = 1
    while i <= x:
    yield from range(0, i)
    i += 1
    才會在 for i in foo(4): print(i) iterate後得到
    0
    0
    1
    0
    1
    2
    0
    1
    2
    3
    是需要改什麼東西嗎,還是執行環境上的差異呢

    ReplyDelete
    Replies
    1. 因為yield與yield from不一樣。

      呼叫range()、回傳的是個range物件。直接print,就印出range物件。
      >>> r = range(0, 3)
      >>> print(r)
      range(0, 3)

      用yield from的話,會從range物件(符合迭代協定)拿出一個個元素。

      Delete