python - 将组合函数转换为生成器

时间:2016-05-15 15:00:35

标签: python generator

我有一个函数可以创建列表项的所有组合,将其表示为列表列表:

def makeCombos(arr):
  yield (sum([map(list, combinations(arr, i)) for i in range(len(arr) + 1)], []))

调用makeCombos([1,2,3,4,5])给了我一个生成器对象,但调用.next()一次不给我一个组合,它给了我整个组合列表。

如何将其转换为我可以调用的生成器函数?

2 个答案:

答案 0 :(得分:3)

sum(iterable, [])不会创建列表列表。它实际上使事情变得平坦。

yield (sum(...))在这一行中您只是产生了一个项目,即所有组合的扁平化列表。

对于Python 2.X sum([(map(list, combinations(arr, i))) ...])将起作用,但在Python 3.X map中不再返回列表。相反,它返回一个地图对象。因此,如果Python 3.X上的任何人只需将其转换为list(map(.....)),以便在3.X上运行。

我认为你真正想要的是这样的:

from itertools import combinations
def makeCombos(arr):
     for i in range(len(arr) + 1):
         for combo in map(list, combinations(arr, i)):
            yield combo

#Or call next 

combos = makeCombos([1, 2, 3, 4, 5])
for combo in combos:
     print combo

单行评论的替代方案:

我们可以返回生成器对象,而不是屈服,而不是像yield一样循环。

e.g。 -

from itertools import combinations

def makeCombos(arr):

     return (combo for i in range(len(arr) + 1) for combo in map(list, combinations(arr, i)))

combos = makeCombos([1, 2, 3, 4, 5])
....

至于这个" Pythonic"我不会这么说。我实际上更喜欢嵌套的forloop,它更具可读性。

虽然,我们仍然可以通过做一些"技巧"

来尝试清理它/压缩它
from itertools import combinations as cs #or some other name)

def makeCombos(arr):

    return (c for i in range(len(arr) + 1) for c in map(list, cs(arr, i)))

但是,现在您已经失去了所有可读性,这看起来像是您在 Perl 中看到的内容。 (恐怖!)

输出:

[]
[1]
[2]
[3]
[4]
[5]
[1, 2]
[1, 3]
[1, 4]
[1, 5]
[2, 3]
[2, 4]
[2, 5]
[3, 4]
[3, 5]
[4, 5]
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 3, 4]
[1, 3, 5]
[1, 4, 5]
[2, 3, 4]
[2, 3, 5]
[2, 4, 5]
[3, 4, 5]
[1, 2, 3, 4]
[1, 2, 3, 5]
[1, 2, 4, 5]
[1, 3, 4, 5]
[2, 3, 4, 5]
[1, 2, 3, 4, 5]

答案 1 :(得分:1)

itertools已经有了一种将iterables连接在一起的方法:它被称为chain。你想要的是如下:

def makeCombos(arr):
    return chain.from_iterable(combinations(arr, i) for i in range(len(arr) + 1))

在我看来,简单,简短,相当Pythonic。