繁体   English   中英

翻译递归解决方案以查找列表的所有子集

[英]translating a recursive solution to find all subsets of a list

我想知道是否存在相对简单的方法来迭代查找列表的所有子集。 使用递归,这很容易做到并且非常简洁。

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是有用的,但如果可能的话,我希望找到不需要的解决方案。

由于存在2**n个子集( n是列表的长度)。 您可以创建一个从02**(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移位所需的数量,然后按该位进行按位运算。 例如,要检查是否在423设置了third位,可以执行以下操作:

number = 423
if number & 1<<3:
    print 'this bit is set'

如@ sudomakeinstall2所述,您可以使用02**(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]))

本质上,构建子集列表与构建大小为1到输入长度的所有组合的列表相同。 因此,一种解决方案涉及使用itertools

import itertools

def all_subsets(l):
    res = []
    for subset_len in range(1, len(l)+1):
        for combo in itertools.combinations(l, subset_len):
            res.append(combo)
    return res

data = [1, 2, 3, 4]
print(all_subsets(data))

请在此处查看实际操作: http : //ideone.com/geTdUS

在这种情况下,我避免过多使用递归的主要原因是因为您可能最终会获得大量的递归调用,并且Python中的最大递归深度可能不够深。 就是说,我不确定这个ittools解决方案可以使用多大的输入大小。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM