2012-07-16 44 views
8

我想知道如何編寫python函數,它可以使生成器產生另一個生成器或迭代器(它也可以產生另一個生成器/ iterables ...可能是無限的)。Python:函數來展平包含另一個發生器的發生器

這裏是例如:

gen(gen(1,2,3), gen(4,5,6), [7,8,9], [gen(10,11,12), gen(13,14,15)])

注:gen - 用於發電機對象,gen後括號之間的內容是將發電機gen產量數據。

「扁平化」後,預期的結果: gen(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)

這是必要的扁平化函數返回發電機呢! (因爲否則,發電機的先前使用將毫無意義)。

請注意,我使用python 3.

謝謝!

回答

12

最簡單的方法是遞歸展平函數。假設你要下降到除了字符串每次迭代,你可以這樣做:

def flatten(it): 
    for x in it: 
     if (isinstance(x, collections.Iterable) and 
      not isinstance(x, str)): 
      for y in flatten(x): 
       yield y 
     else: 
      yield x 

在Python 3.3開始,你也可以寫

def flatten(it): 
    for x in it: 
     if (isinstance(x, collections.Iterable) and 
      not isinstance(x, str)): 
      yield from flatten(x) 
     else: 
      yield x 
+0

非常感謝!隨着我的嘗試,我非常接近你的:-)問候! – JoshuaBoshi 2012-07-16 11:28:38

+0

+1 - 我一直忘記'從'產量,這是一個很好的提醒。 – 2012-07-16 11:40:36

+2

@JonClements:你「忘記」一個Python版本的功能,至今尚未發佈?我很驚訝。 :) – 2012-07-16 12:15:34

0

的非遞歸方法本質上是一個展開遞歸方法,使用堆棧:

def flatten(it): 
    stack = [] 
    it = iter(it) 
    while True: 
     try: 
      x = next(it) 
     except StopIteration: 
      if stack: 
       it = stack.pop() 
       continue 
      else: 
       return 
     if isinstance(x, collections.Iterable) and not isinstance(x, str): 
      stack.append(it) 
      it = iter(x) 
     else: 
      yield x