【问题标题】:Recursively find all combinations of list递归查找列表的所有组合
【发布时间】:2020-12-07 11:42:41
【问题描述】:

问题陈述

我想从我的列表中取出所有可能的组合(包括空列表)。

到目前为止我的代码是:

def combination(l):
    result = []
    for item in range(len(l)):
        cut_list = l[:item] + l[item + 1:]
        if len(cut_list) > 1:
            combination(cut_list)
        elif len(cut_list) == 1:
            result += cut_list
    return result


print(combination([1, 2, 3]))

我的输出是一个空列表

[]

我想要这个输出:

[[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

我很确定我的回报是不对的。

非常感谢任何帮助。

【问题讨论】:

  • 您的return result 看起来不错,只是一旦返回,您就什么也没做。
  • 详细说明@quamrana 的评论:主要的明显错误在于递归调用combination(cut_list)。此行进行递归调用;递归调用执行计算以找到cut_list 的组合;但递归调用的返回值被丢弃。相反,您可能应该写类似result += combination(cut_list) 的东西。至少这应该给你一个不只是一个空列表的结果。不过,算法的整体逻辑并不完全正确,因此结果仍不会完全符合您的要求,但这是一个开始。

标签: python list recursion return combinations


【解决方案1】:

可以这样找到递归关系:“列表l的组合要么使用l的最后一个元素,要么不使用。”

所以我们递归地找到子列表l[:-1](包含除最后一个元素之外的所有元素的子列表)的组合;然后我们要么添加或不添加最后一个元素。

递归版本

这个递归需要一个基本情况。基本情况是:如果列表为空,则唯一的组合是空组合。

def combinations(l):
    if l:
      result = combinations(l[:-1])
      return result + [c + [l[-1]] for c in result]
    else:
      return [[]]

print(combinations([1,2,3]))
# [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

迭代版本

递归关系很大,但不需要递归; for-loops 可以很好地重复应用递归关系。

def combinations(l):
  result = [[]]
  for x in l:
    result = result + [c + [x] for c in result]
  return result

print(combinations([1,2,3]))
# [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

【讨论】:

  • 你好,Steff... 我们可以做同样的功能,但只返回 N 个元素的组合吗?比如 N = 2... 那么我们期望得到的是 [1, 2], [1, 3], [2, 3]
  • @lucasbbs 当然可以。对于递归版本,添加参数n 与所需元素的数量一样简单(并小心在递归调用中正确更新它)。我建议您提出一个新问题(并在此处链接,以便我回答);但实际上,这个问题已经在 stackoverflow 上提出并回答了。例如:How to get all combinations of length n
【解决方案2】:

试试这个:

In [24]: import itertools

In [25]: l
Out[25]: [1, 2, 3]

In [26]: [sublist for item in [[list(x) for x in itertools.combinations(l,n)] for n in range(len(l)+1)] for sublist in item]
Out[26]: [[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

【讨论】:

  • 这是我正在寻找的输出,但我的目标是在没有 itertools 的情况下做到这一点
【解决方案3】:

使用嵌套循环

first_list = [1,2,3]
second_list = ['a', 'b']
L = [[]]
for f in first_list:
    for s in second_list:
        L.append((f,s))

左:

[[], (1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b')]

【讨论】:

    【解决方案4】:

    这就是你想做的?

    l = [3, 22, 10, 15, 32, 10, 5]
    
    
    def f(ml: list):
        a = []
        for i1 in ml:
            for i2 in ml:
                if not i1 + i2 in a:
                    a.append(i1 + i2)
        return a
    
    
    print(f(l))
    
    

    [6, 25, 13, 18, 35, 8, 44, 32, 37, 54, 27, 20, 42, 15, 30, 47, 64, 10]

    【讨论】:

      【解决方案5】:

      您也应该传递您的result 列表,如下所示。但我认为这个递归函数并没有做你想做的事情。

      def combination(l, result=[]):
          for item in range(len(l)):
              cut_list = l[:item] + l[item + 1:]
              if len(cut_list) > 1:
                  combination(cut_list, result)
              elif len(cut_list) == 1:
                  result += cut_list
          return result
      
      
      print(combination([3, 22, 10, 15, 32, 10, 5]))
      

      结果:

      >>> python3 test.py 
      [5, 10, 5, 32, 10, 32, 5, 10, 5, 15, 10, 15, 5, 32, 5, 15, 32, ...
      

      您无需递归即可获得所有组合/排列:

      排列:

      import itertools
      stuff = [1, 2, 3]
      for L in range(0, len(stuff)+1):
          for subset in itertools.permutations(stuff, L):
              print(subset)
      

      输出:

      >>> python3 test.py 
      ()
      (1,)
      (2,)
      (3,)
      (1, 2)
      (1, 3)
      (2, 1)
      (2, 3)
      (3, 1)
      (3, 2)
      (1, 2, 3)
      (1, 3, 2)
      (2, 1, 3)
      (2, 3, 1)
      (3, 1, 2)
      (3, 2, 1)
      

      组合(此机制与您在问题中的描述相匹配):

      import itertools
      stuff = [1, 2, 3]
      for L in range(0, len(stuff)+1):
          for subset in itertools.combinations(stuff, L):
              print(subset)
      

      输出:

      >>> python3 test.py 
      ()
      (1,)
      (2,)
      (3,)
      (1, 2)
      (1, 3)
      (2, 3)
      (1, 2, 3)
      

      编辑:

      当然,你可以从我下面的例子中创建一个函数,你可以得到一个嵌套列表的结果。

      代码:

      import itertools
      
      def combination(l):
          result = []
          for L in range(0, len(l)+1):
              for subset in itertools.combinations(l, L):
                  result.append(list(subset))
          return result
      
      print(combination([1, 2, 3]))
      

      输出:

      >>> python3 test.py 
      [[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
      

      EDIT_2:

      没有itertools模块的解决方案:

      代码:

      def combinations(return_len, iterable):
          if not return_len:
              return [[]]
          if not iterable:
              return []
      
          head = [iterable[0]]
          tail = iterable[1:]
          new_comb = [head + list_ for list_ in combinations(return_len - 1, tail)]
      
          return new_comb + combinations(return_len, tail)
      
      
      input_list = [1, 2, 3]
      result = []
      
      for n in range(0, len(input_list) + 1):
          for single_result in combinations(n, input_list):
              result.append(single_result)
      
      print(result)
      

      输出:

      >>> python3 test.py 
      [[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
      

      【讨论】:

      • 我想要这样的输出 [[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [ 1, 2, 3]] 使用递归并且在我的函数中只有一个给定参数
      • 我已经编辑了我的答案。现在输入/输出格式与您的问题相同!
      • 没有itertools也可以吗?
      • 您的第一个代码不能正常工作,因为可变的可选参数。尝试调用该函数两次,第二次会得到垃圾结果。另见:Python documentation / Gotchas / Mutable default arguments
      • 我知道使用可变选项参数,我知道它非常危险。我没有说这是最好的解决方案,我只是想表明问题中的“原始”递归函数不正确(不仅return 语句有问题)。但另一方面,感谢您的评论。
      【解决方案6】:

      我会这样做(作为生成器):

      def combinations(aList):
          yield []
          for i,v in enumerate(aList,1):
              yield from ([v]+c for c in combinations(aList[i:]))
          
      
      for combo in combinations([1,2,3]): print(combo)
      
      []
      [1]
      [1, 2]
      [1, 2, 3]
      [1, 3]
      [2]
      [2, 3]
      [3]
      

      或作为列表生成器:

      def combinations(aList):
          return [[]] + [ [v]+c for i,v in enumerate(aList,1) 
                                for c   in combinations(aList[i:]) ]
      
      print( combinations([1,2,3]) )
      
      [[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-10-14
        • 2015-08-11
        • 1970-01-01
        • 2017-11-27
        • 2012-04-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多