Python递归函数显示给定集的所有子集

时间:2014-10-13 03:13:10

标签: python arrays list recursion functional-programming

我有以下python函数来打印数字列表的所有子集:

def subs(l):
    if len(l) == 1:
        return [l]
    res = []
    for sub in subs(l[0:-1]):
        res.append(sub)
        res.append([l[-1]])
        res.append(sub+[l[-1]])
    return res

li = [2, 3, 5, 8]
print(subs(li))

返回:

[[2], [8], [2, 8], [5], [8], [5, 8], [2, 5], [8], [2, 5, 8], [3], [8], [3, 8], [5], [8], [5, 8], [3, 5], [8], [3, 5, 8], [2, 3], [8], [2, 3, 8], [5], [8], [5, 8], [2, 3, 5], [8], [2, 3, 5, 8]]

这不是预期的答案。看起来python将列表l引入函数中。所以当我追加l [-1]时,它会附加原始列表的最后一个元素,而不是发送到递归方法的较小列表。有什么方法可以解决这个问题吗?

这可能是使用元组解决的,但我想知道是否有使用列表的解决方案。

6 个答案:

答案 0 :(得分:7)

def subs(l):
    if l == []:
        return [[]]

    x = subs(l[1:])

    return x + [[l[0]] + y for y in x]

结果:

>>> print (subs([1, 2, 3]))
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]

答案 1 :(得分:1)

有一个方便的Python模块可以提供帮助:

import itertools
def subs(l):
    res = []
    for i in range(1, len(l) + 1):
        for combo in itertools.combinations(l, i):
            res.append(list(combo))
    return res

结果是:

>>> subs([1,2,3])
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

答案 2 :(得分:1)

实际上,我最初认为Python引用调用没有问题。在这种情况下,l [-1]在所有递归调用中都是8。但是在递归调用中l [-1]分别为3,5,8。这个修改过的函数解决了这个问题:

def subs(l):
    if len(l) == 1:
        return [l]
    res = []
    subsets = subs(l[0:-1])
    res = res+subsets
    res.append([l[-1]])
    for sub in subsets:
        res.append(sub+[l[-1]])
    return res

返回:

[[2], [3], [2, 3], [5], [2, 5], [3, 5], [2, 3, 5], [8], [2, 8], [3, 8], [2, 3, 8], [5, 8], [2, 5, 8], [3, 5, 8], [2, 3, 5, 8]]

答案 3 :(得分:1)

改进@Miguel Matos的答案

def subsets(set_inp):
    if set_inp == []:
        return [[]]
    x = subsets(set_inp[1:])

    return sorted( x + [[set_inp[0]] + y for y in x])
print(subsets([1,2,3]))

答案 4 :(得分:0)

使用@Miguel Matos的想法 我们可以按字典顺序获得这些信息,

def foo(l, p = [], d = {}):
    if len(l)==0: 
        return [[]]

    x = foo(l[:-1])

    return x+ [[l[-1]] + y for y in x]
  

返回

     

[[],[1],[2],[2、1],[3],[3、1],[3、2],[3、2、1],[4],[ 4,1],[4,2],[4,2,1],[4,3],[4,3,1],[4,3,2],[4,3,2,1] ]

答案 5 :(得分:0)

通过使用lambda函数和map,可以避免使用理解或for循环。

我认为这是Python中适当的“函数式” powerset函数:

def powerSet(input):


# at tree leaf, return leaf
if len(input)==0:
    return [[]];

# if not at a leaf, trim and recurse
# recursion is illustrated as follows:
# e.g. S = {1,2,3}
# S_trim = S without first element:
# {(),(2),(3),(2,3)}
# S_trim concatenated with first element:
# {(1),(1,2),(1,3),(1,2,3)}
# we keep the character sliced from front and concat it 
# with result of recursion

# use map to apply concatenation to all output from powerset

leading = (input[0])
new_input = input[1:len(input)]


ps1 = list((powerSet(new_input)))
# concatenate over powerset-ed set
ps2 = map(lambda x: [leading]+x,ps1) 

ps_list = list(map(lambda x: list(x),ps2))

return ps1+ ps_list