我想知道是否有一种相对简单的方法可以迭代地查找列表的所有子集。使用递归,这很容易完成,非常简洁......
def partial(alist, pos, chosen):
if pos == len(alist):
return [chosen]
else:
return partial(a list, pos+1, chosen) \
+ partial(alist, pos+1, chosen + [alist[pos]])
这将返回包含列表所有子集的列表列表。
有没有办法迭代地做这样的事情而不会过于复杂,或者递归是最好的方法?一些伪代码或解释迭代执行此操作的方法会有所帮助。我知道itertools
是有帮助的,但如果可能的话,我想要一个解决方案而不需要它。
答案 0 :(得分:4)
因为有2**n
个子集(n
是列表的长度)。您可以创建从0
到2**(n-1)
的计数器。然后通过在计数器二进制形式中添加相应位设置为1
的元素,在每次迭代中创建一个列表(这是一个子集)。
counter = 5
binary_form = 101
you create a subset using first and third element of the original list
counter = 7
binary_form = 111
you create a subset using first, second and third element of the original list
可以像这样实现这个,
result = []
A = [1,2,3,4]
for i in range(0,2**len(A)):
binary = bin(i)[2:]
binary = '0'*(len(A)-len(binary)) + binary
subset = [ A[i] for i,x in enumerate(binary) if x=='1' ]
print binary,subset
result.append(subset)
print result
输出
0000 []
0001 [4]
0010 [3]
0011 [3, 4]
0100 [2]
0101 [2, 4]
0110 [2, 3]
0111 [2, 3, 4]
1000 [1]
1001 [1, 4]
1010 [1, 3]
1011 [1, 3, 4]
1100 [1, 2]
1101 [1, 2, 4]
1110 [1, 2, 3]
1111 [1, 2, 3, 4]
但正如评论和其他答案中所提到的,最好不要制作二进制字符串。如果要检查是否设置了某个位,可以将1
移动所需的量,然后按位数和该数字进行。例如,要检查third
中是否设置了423
位,您可以执行此操作:
number = 423
if number & 1<<3:
print 'this bit is set'
答案 1 :(得分:2)
正如@ sudomakeinstall2所提到的,您可以使用0
到2**(n-1)
的计数器来遍历列表,并将其用作掩码从alist
中选择值。
def partial(alist):
result = []
for i in range(2 ** len(alist)): # iterate over all results
tmp = []
for j in range(len(alist)):
if (2 ** j) & i: # use bit mask to pick the value
tmp.append(alist[j])
result.append(tmp)
return result
结果可能非常大,您可能想要创建一个生成器以便懒惰地评估。
使用列表理解和生成器:
def partial(alist):
for i in range(2 ** len(alist)):
yield [alist[j] for j in range(len(alist)) if 2 ** j & i]
您可以使用
进行调用for i in partial([1, 2, 3]):
print(i)
或
result = list(partial([1, 2, 3]))
答案 2 :(得分:1)
基本上构建子集列表与构建大小1到输入长度的所有组合的列表相同。因此,一个解决方案涉及使用itertools:
def sortable(column, title = nil)
if column == 'category' then
title ||= 'Category'
column == 'category_id'
direction = (column == params[:sort] && params[:direction] == "asc") ? "desc" : "asc"
link_to title, :sort => 'category_id', :direction => direction
else
title ||= column.titleize
direction = (column == params[:sort] && params[:direction] == "asc") ? "desc" : "asc"
link_to title, :sort => column, :direction => direction
end
end
在此处查看此操作:http://ideone.com/geTdUS
在这种情况下,我避免过多使用递归的主要原因是因为你可能最终会进行大量的递归调用,并且Python中的最大递归深度可能不够深。这就是说我不完全确定这个itertools解决方案的输入大小有多大。