我已经编写了一个名为size_subsets
的函数,它在传递城市列表(数字)时返回特定大小的所有子集。但是,使用izip()
而不是两个for-yield块重新启动函数会完全破坏行为。
下面的第二种方法使用izip()
重新设置第一种方法,但由于某种原因,它在顶层没有返回任何内容。任何人都可以帮我弄清楚这是为什么吗?
打印语句显示某些(并非所有)正确的子集确实在size_subsets_broken
的递归最底层产生,但即使这些也没有达到最高级别某种原因。
def size_subsets(cities, size, sofar):
if not size:
yield sofar
return
elif len(cities) < size:
return
else:
curr_city = cities.pop()
for a in size_subsets(cities[:], size - 1, sofar | {curr_city}):
yield a
for b in size_subsets(cities[:], size, sofar):
yield b
def size_subsets_broken(cities, size, sofar):
if not size:
yield sofar
return
elif len(cities) < size:
return
else:
curr_city = cities.pop()
inclusive = size_subsets_broken(cities[:], size - 1, sofar | {curr_city})
exclusive = size_subsets_broken(cities[:], size, sofar)
for incl_subset, excl_subset in izip(inclusive, exclusive):
yield incl_subset
yield excl_subset
print list(size_subsets([1, 2, 3], 2, set())) # [set([2, 3]), set([1, 3]), set([1, 2])]
print list(size_subsets_broken([1, 2, 3], 2, set())) # []
答案 0 :(得分:1)
我怀疑你误解了izip()
的工作原理。当最短输入可迭代用尽时,它就会停止,并且没有理由相信您的inclusive
和exclusive
总是具有相同的长度。
>>> from itertools import izip
>>> for i in izip(range(10), [6]):
... print i
(0, 6)
>>> for i in izip(range(10), []):
... print i
请注意,第一个示例中只有一个输出,而第二个示例中根本没有输出。这都是预期的。
对size_subsets_broken()
的顶级调用会创建一个生成器 - 迭代器(gi
)对象。对list()
的调用迫使后者做某事。
它使用参数(忽略inclusive
)exclusive
和gi
创建sofar
和[1, 2], 1
[1, 2], 2
个对象。 izip()
然后尝试将它们组合在一起。
izip()
首先尝试从inclusive
获取一个值(最终无法提供任何内容,这就是为什么顶级gi
也不会产生任何结果 - 实际上,它甚至都没有试图强制exclusive
产生任何东西,因为inclusive
为空 - izip()
“只有在最短的输入迭代用尽时才会停止”。
回想一下,顶级inclusive
的参数是[1, 2], 1
。它为gi
和[1], 0
创建[1], 1
个对象。 其 izip()
通过[1], 0
测试推送if not size
分支以产生一个值。因此,izip()
继续推动[1], 1
分支获取值。
反过来会创建[], 0
和[], 1
gi
个分支。另一层izip()
推送其中的第一层以产生一个值(再次通过if not size
测试),但第二个分支因if len(cities) < size: return
而没有产生任何值。因此,izip()
一级向上放弃,而它所属的gi
不会产生任何效果。
传播链:在每个级别,izip()
至少找到一个空迭代器,因此永远不会输入for ... in izip(...):
循环的主体(在任何级别)。
顺便说一下,izip()
这不是问题。在此算法中尝试使用izip()
是没有意义的。