【问题标题】:Python recursive function to display all subsets of given setPython递归函数显示给定集合的所有子集
【发布时间】:2014-12-07 13:41:49
【问题描述】:

我有以下 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] 时,它会追加原始列表的最后一个元素,而不是发送到递归方法中的较小列表。有没有办法解决这个问题?

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

【问题讨论】:

  • 预期的答案是什么?这看起来就是你要找的东西。显然这种方法在这个过程中也积累了很多重复。
  • 你想要像[list(itertools.permutations(li[:x])) for x in range(len(li))] 这样的一维列表吗?
  • @Cocksure 我的错误,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 在子集中: res.append(sub+[l[-1]]) return res

标签: python arrays list recursion functional-programming


【解决方案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]]

【讨论】:

  • 这与itertools module page 上给出的powerset 的配方基本相同——但他们的版本实际上返回了一个迭代器,这比一个列表要好得多,以获得潜在的巨大结果。
【解决方案2】:

实际上,我最初认为的 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】:
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]]

【讨论】:

  • 我希望结果按字典顺序排序?
  • @Nidhi 您可能会注意到此解决方案按字典顺序对结果进行排序。只需置换返回即可获得字典顺序:return [[l[0]] + y for y in x] + x
【解决方案4】:

改进@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]))

【讨论】:

    【解决方案5】:

    使用@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] ]

    【讨论】:

      【解决方案6】:

      您可以通过使用 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    
      

      【讨论】:

        【解决方案7】:

        继续 @Miguel 和 @Abdul 提供的答案...以下函数确保按字典顺序输出。

        def subset(A):
            if A == []:
                return [[]]
            sub = subset(A[:-1])
            return sub + [rem + [A[-1]] for rem in sub] 
        
        tests = [[], [1], [1,2], [1,2,3]]
        for test in tests:
            print(subset(test))
        
        RESULT
        
        [[]]
        [[], [1]]
        [[], [1], [2], [1, 2]]
        [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
        

        【讨论】:

          猜你喜欢
          • 2016-02-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多