[英]What's the most memory efficient way to generate the combinations of a set in python?
This is the code I came up with: 这是我提出的代码:
def combinations(input):
ret = ['']
for i in range(len(input)):
ret.extend([prefix+input[i] for prefix in ret])
return ret
This algorithm is O(2^n) time, but can space be reduced? 这个算法是O(2 ^ n)时间,但可以减少空间吗? I heard using
yield
might work, but having trouble thinking through how to implement with yield
. 我听说使用
yield
可能会有效,但是在思考如何用yield
实现时却很困难。 Please don't use the built in combination function -- I would like to see how it's implemented. 请不要使用内置组合功能 - 我想看看它是如何实现的。
Your question specifically said you wanted to see what the code would look like, so here is a hand coded example of an O(n) space solution: 你的问题明确表示你想看看代码会是什么样子,所以这里是一个O(n)空间解决方案的手工编码示例:
def combinations(input_list, acc=''):
if not input_list:
yield acc
return
next_val = input_list[0]
for rest in combinations(input_list[1:], acc):
yield rest
acc += next_val
# In python 3.2, you can use "yield from combinations(input_list[1:], acc)"
for rest in combinations(input_list[1:], acc):
yield rest
Note that the substring arithmetic might be expensive (since it has to copy the string many times), so here is a slightly more efficient version in terms of complexity: 请注意,子字符串算法可能很昂贵(因为它必须多次复制字符串),因此就复杂性而言,这是一个稍微高效的版本:
def combinations(input_list, acc='', from_idx=0):
if len(input_list) <= from_idx:
yield acc
return
next_val = input_list[from_idx]
for rest in combinations(input_list, acc, from_idx + 1):
yield rest
acc += next_val
# In python 3.2, you can use "yield from combinations(input_list[1:], acc)"
for rest in combinations(input_list, acc, from_idx + 1):
yield rest
I'm not using Python 3.2, but if you were you could write it like this: 我没有使用Python 3.2,但如果你是,你可以像这样写:
def combinations(input_list, acc='', from_idx=0):
if len(input_list) <= from_idx:
yield acc
return
next_val = input_list[from_idx]
yield from combinations(input_list, acc, from_idx + 1)
acc += next_val
yield from combinations(input_list, acc, from_idx + 1)
I should also note that this is purely academic since itertools.combinations
does a fine job and works for a wider array of inputs (including generator expressions). 我还应该注意到,这纯粹是学术性的,因为
itertools.combinations
做得很好,适用于更广泛的输入(包括生成器表达式)。
Something like this should do it: 这样的事情应该这样做:
>>> print list(itertools.combinations({1, 2, 3, 4}, 3))
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
>>>
You can use yield
in your code like so: 您可以在代码中使用
yield
,如下所示:
def combinations(input):
ret = ['']
yield ''
for i in range(len(input)):
for prefix in ret:
combination = prefix+input[i]
ret.extend(combination)
yield combination
But it doesn't save you any space. 但它不会为您节省任何空间。
The itertools.combinations documentation shows a (much) more complicated algorithm that works in constant space - the actual implementation is in C, but claims to be equivalent. itertools.combinations文档显示了一个(更多)更复杂的算法,它在恒定的空间中工作 - 实际的实现是在C中,但声称是等效的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.