我有一个函数可以创建列表项的所有组合,将其表示为列表列表:
def makeCombos(arr):
yield (sum([map(list, combinations(arr, i)) for i in range(len(arr) + 1)], []))
调用makeCombos([1,2,3,4,5])
给了我一个生成器对象,但调用.next()
一次不给我一个组合,它给了我整个组合列表。
如何将其转换为我可以调用的生成器函数?
答案 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。