【问题标题】:How to get all possible combinations of a list’s elements?如何获得列表元素的所有可能组合?
【发布时间】:2010-10-02 16:00:14
【问题描述】:

我有一个包含 15 个数字的列表,我需要编写一些代码来生成这些数字的所有 32,768 个组合。

我发现some code(通过谷歌搜索)显然可以满足我的要求,但我发现代码相当不透明并且对使用它持谨慎态度。另外,我觉得必须有一个更优雅的解决方案。

我唯一想到的就是循环遍历十进制整数 1-32768 并将它们转换为二进制,然后使用二进制表示作为过滤器来挑选合适的数字。

有人知道更好的方法吗?使用map(),可能吗?

【问题讨论】:

  • 读者应该注意,列表项是否唯一是一个非常重要的考虑因素,因为许多算法会过度计算某些子集(例如'abccc' -> ['', 'a', 'b', 'c', 'c', 'c', 'ac', 'ac', 'ac', ...]. 一个简单的解决方法是将所有元素推入集合 在得到它们的排列之前。
  • @ninjagecko 使用 Set 库效率不高,因为每个库的最佳时间都是 O(n)。因此将 n 个函数添加到一个集合实际上是 O(n^2)!
  • 从仔细阅读问题来看,似乎 OP 要求的是他的 15 个数字列表中的 PowerSet,而不是所有组合。我想这可能就是为什么答案到处都是。
  • @Scott Biggs:你确定你在这里了解 Python 吗?集合插入和查找是 O(1) 平均情况。它们就像字典。他们使用散列。 Python 没有特殊的集合库(它在标准库中)。我们在这里插入数字而不是函数。 (使用 O(2^n) 内存仍然效率低下;对于想要组合而不是 powerset 的人来说,正确的解决方案是简单的递归实现,或product 等)

标签: python combinations


【解决方案1】:

This answer 遗漏了一个方面:OP 要求所有组合...而不仅仅是长度“r”的组合。

所以你要么必须遍历所有长度“L”:

import itertools

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

或者——如果你想变得时髦(或者让阅读你代码的人的大脑弯曲)——你可以生成“combinations()”生成器链,并对其进行迭代:

from itertools import chain, combinations
def all_subsets(ss):
    return chain(*map(lambda x: combinations(ss, x), range(0, len(ss)+1)))

for subset in all_subsets(stuff):
    print(subset)

【讨论】:

  • 感谢您的支持!在我发布上述回复后的几周内,我发现 Ben 正在寻找的概念的名称是原始 15 个项目集的“powerset”。事实上,标准python“itertools”文档页面上给出了一个示例实现:docs.python.org/library/itertools.html(grep for “powerset”)。
  • 对于读到这里的任何人:itertools documentation 的食谱部分中的 powerset() 生成器函数更简单,可能使用更少的内存,并且可能比此处显示的实现。
  • 是否可以按字典顺序生成所有组合?
  • @guik:我 99% 确定 itertools.combinations 在它生成的列表中保留了项目顺序。因此,如果输入是按词法排序的,那么每个输出也将是。
  • @ENIAC-6 :这就是 Python 使用一个元素打印元组的方式。 (逗号不是“那里”,直到您尝试打印它。)所以您有选择:1:首先将项目转换为列表:print(list(item)) 或 2:使用 ",".join(items) 以避免单元素逗号.
【解决方案2】:

看看itertools.combinations:

itertools.combinations(iterable, r)

返回 r 个长度的元素子序列 输入可迭代。

组合按字典排序顺序发出。所以,如果 输入迭代被排序, 组合元组将在 排序顺序。

自 2.6 起,包含电池!

【讨论】:

  • 你可以全部列出来。 list(itertools.combinations(iterable, r))
  • 有什么不需要r,即任意长度的元素子序列的组合。
  • 这非常好,并指出真正解决了我的问题的原因是itertools.combination_with_replacement
  • 函数写intertools.combinations_with_replacement
【解决方案3】:

这是一个懒惰的单线,也使用 itertools:

from itertools import compress, product

def combinations(items):
    return ( set(compress(items,mask)) for mask in product(*[[0,1]]*len(items)) )
    # alternative:                      ...in product([0,1], repeat=len(items)) )

这个答案背后的主要思想:有 2^N 组合 - 与长度为 N 的二进制字符串的数量相同。对于每个二进制字符串,您选择与“1”相对应的所有元素。

items=abc * mask=###
 |
 V
000 -> 
001 ->   c
010 ->  b
011 ->  bc
100 -> a
101 -> a c
110 -> ab
111 -> abc

需要考虑的事项:

  • 这要求您可以在items 上调用len(...)(解决方法:如果items 类似于生成器之类的可迭代对象,请先使用items=list(_itemsArg) 将其转换为列表)
  • 这要求items 上的迭代顺序不是随机的(解决方法:不要发疯)
  • 这要求项目是唯一的,否则{2,2,1}{2,1,1} 都将折叠为{2,1}(解决方法:使用collections.Counter 作为set 的直接替代品;它基本上是一个多重集合。 .. 虽然你可能需要稍后使用tuple(sorted(Counter(...).elements())),如果你需要它是可散列的)

演示

>>> list(combinations(range(4)))
[set(), {3}, {2}, {2, 3}, {1}, {1, 3}, {1, 2}, {1, 2, 3}, {0}, {0, 3}, {0, 2}, {0, 2, 3}, {0, 1}, {0, 1, 3}, {0, 1, 2}, {0, 1, 2, 3}]

>>> list(combinations('abcd'))
[set(), {'d'}, {'c'}, {'c', 'd'}, {'b'}, {'b', 'd'}, {'c', 'b'}, {'c', 'b', 'd'}, {'a'}, {'a', 'd'}, {'a', 'c'}, {'a', 'c', 'd'}, {'a', 'b'}, {'a', 'b', 'd'}, {'a', 'c', 'b'}, {'a', 'c', 'b', 'd'}]

【讨论】:

    【解决方案4】:

    在@Dan H 高度支持的answer 下的cmets 中,提到了itertools documentation 中的powerset() 配方——包括Dan himself 的配方。 然而,到目前为止,还没有人将其发布为答案。由于它可能是解决问题的最佳方法之一,如果不是最好的方法,并且从另一位评论者那里得到little encouragement,它如下所示。该函数生成所有可能的每个长度的列表元素的唯一组合(包括那些包含零和所有元素的组合)。

    注意:如果稍有不同,目标是仅获取唯一元素的组合,请将行 s = list(iterable) 更改为 s = list(set(iterable)) 以消除任何重复元素。无论如何,iterable 最终变成list 的事实意味着它将与生成器一起使用(与其他几个答案不同)。

    from itertools import chain, combinations
    
    def powerset(iterable):
        "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
        s = list(iterable)  # allows duplicate elements
        return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
    
    stuff = [1, 2, 3]
    for i, combo in enumerate(powerset(stuff), 1):
        print('combo #{}: {}'.format(i, combo))
    

    输出:

    combo #1: ()
    combo #2: (1,)
    combo #3: (2,)
    combo #4: (3,)
    combo #5: (1, 2)
    combo #6: (1, 3)
    combo #7: (2, 3)
    combo #8: (1, 2, 3)
    

    【讨论】:

    • list() 转换首先是为了什么?
    • @Alexander:允许确定迭代的长度。
    【解决方案5】:

    这一行为您提供所有组合(如果原始列表/集包含 n 不同元素,则在 0n 项目之间)并使用本机方法 itertools.combinations

    Python 2

    from itertools import combinations
    
    input = ['a', 'b', 'c', 'd']
    
    output = sum([map(list, combinations(input, i)) for i in range(len(input) + 1)], [])
    

    Python 3

    from itertools import combinations
    
    input = ['a', 'b', 'c', 'd']
    
    output = sum([list(map(list, combinations(input, i))) for i in range(len(input) + 1)], [])
    

    输出将是:

    [[],
     ['a'],
     ['b'],
     ['c'],
     ['d'],
     ['a', 'b'],
     ['a', 'c'],
     ['a', 'd'],
     ['b', 'c'],
     ['b', 'd'],
     ['c', 'd'],
     ['a', 'b', 'c'],
     ['a', 'b', 'd'],
     ['a', 'c', 'd'],
     ['b', 'c', 'd'],
     ['a', 'b', 'c', 'd']]
    

    在线试用:

    http://ideone.com/COghfX

    【讨论】:

    • 这是一个排列
    • @AdHominem:不,不是。这是所有组合的列表。排列将包括,例如['b', 'a'].
    • TypeError: can only concatenate list (not "map") to list
    • @0x48piraj:感谢您的关注,我因此编辑了我的答案!
    【解决方案6】:

    这是一个使用递归的例子:

    >>> import copy
    >>> def combinations(target,data):
    ...     for i in range(len(data)):
    ...         new_target = copy.copy(target)
    ...         new_data = copy.copy(data)
    ...         new_target.append(data[i])
    ...         new_data = data[i+1:]
    ...         print new_target
    ...         combinations(new_target,
    ...                      new_data)
    ...                      
    ... 
    >>> target = []
    >>> data = ['a','b','c','d']
    >>> 
    >>> combinations(target,data)
    ['a']
    ['a', 'b']
    ['a', 'b', 'c']
    ['a', 'b', 'c', 'd']
    ['a', 'b', 'd']
    ['a', 'c']
    ['a', 'c', 'd']
    ['a', 'd']
    ['b']
    ['b', 'c']
    ['b', 'c', 'd']
    ['b', 'd']
    ['c']
    ['c', 'd']
    ['d']
    

    【讨论】:

    • 可以修改为返回列表列表而不是打印吗?
    • @JamesVickery 是的,您可以查看在函数之外创建一个列表并附加到该列表,或者(更好)使函数成为生成器,看看“yield”关键字:)
    • new_data = copy.copy(data) - 这行在我看来是多余的,它不会影响任何东西
    【解决方案7】:

    这是一种可以轻松转移到所有支持递归的编程语言的方法(没有 itertools、没有 yield、没有列表理解)

    def combs(a):
        if len(a) == 0:
            return [[]]
        cs = []
        for c in combs(a[1:]):
            cs += [c, c+[a[0]]]
        return cs
    
    >>> combs([1,2,3,4,5])
    [[], [1], [2], [2, 1], [3], [3, 1], [3, 2], ..., [5, 4, 3, 2, 1]]
    

    【讨论】:

    • 啊!很好的实现。我从 Prolog 中认出了 HEAD = a[0], TAIL = a[1:]。或者来自 Lisp 的 car = a[0], cdr = a[1:]。我想知道我们是否可以在这里使用 memoization...
    • 是的。列表切片是 O(k),其中 k 是切片的长度。我想人们可以通过在地图中进行查找来加快这一速度,这将使除了第一次之外的所有运行都成为 O(1)。请注意,不应该为了性能而引用此实现。为此,存在更好的实现。此实现仅是为了简单性和对大多数其他语言的可移植性。
    • 比上面的一些丑陋的东西好多了。
    【解决方案8】:

    您可以使用以下简单代码在 Python 中生成列表的所有组合:

    import itertools
    
    a = [1,2,3,4]
    for i in xrange(0,len(a)+1):
       print list(itertools.combinations(a,i))
    

    结果是:

    [()]
    [(1,), (2,), (3,), (4,)]
    [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
    [(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
    [(1, 2, 3, 4)]
    

    【讨论】:

    • 此代码中的错误:不返回空集。可能意味着 xrange(0, ...) 但尚未测试。 编辑:我继续编辑您的答案以修复它。
    • 酷。我试图从公司名称中构建域名来抓取网站,这有助于做到这一点
    【解决方案9】:

    我同意 Dan H 的观点,即 Ben 确实要求 所有 组合。 itertools.combinations() 没有给出所有组合。

    另一个问题是,如果输入的可迭代对象很大,最好返回一个生成器而不是列表中的所有内容:

    iterable = range(10)
    for s in xrange(len(iterable)+1):
      for comb in itertools.combinations(iterable, s):
        yield comb
    

    【讨论】:

    • 很好的例子。我喜欢生成器……我喜欢 Python 因为拥有它们!这个例子一次只有一个combinations() 对象,并且每次产生其中一种组合。 (也许你想在这个周围添加 def 块——作为一个使用示例。)请注意,我的实现(上面给出的带有链())并没有太糟糕:它确实创建了所有 len(iterable) 生成器一次......但它不会一次创建所有 2 ** len(iterable) 组合,因为 - 据我了解 - 在从后续生成器中绘制之前,链“用完”第一个生成器。
    【解决方案10】:

    我想我会为那些在不导入 itertools 或任何其他额外库的情况下寻求答案的人添加此功能。

    def powerSet(items):
        """
        Power set generator: get all possible combinations of a list’s elements
    
        Input:
            items is a list
        Output:
            returns 2**n combination lists one at a time using a generator 
    
        Reference: edx.org 6.00.2x Lecture 2 - Decision Trees and dynamic programming
        """
    
        N = len(items)
        # enumerate the 2**N possible combinations
        for i in range(2**N):
            combo = []
            for j in range(N):
                # test bit jth of integer i
                if (i >> j) % 2 == 1:
                    combo.append(items[j])
            yield combo
    

    简单的收益生成器用法:

    for i in powerSet([1,2,3,4]):
        print (i, ", ",  end="")
    

    上述使用示例的输出:

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

    【讨论】:

    • 我认为这是非常巧妙的解决方案。
    • 这个很漂亮,谢谢分享!
    【解决方案11】:

    这是另一种解决方案(单线),涉及使用 itertools.combinations 函数,但这里我们使用双列表推导(而不是 for 循环或求和):

    def combs(x):
        return [c for i in range(len(x)+1) for c in combinations(x,i)]
    

    演示:

    >>> combs([1,2,3,4])
    [(), 
     (1,), (2,), (3,), (4,), 
     (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), 
     (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), 
     (1, 2, 3, 4)]
    

    【讨论】:

      【解决方案12】:

      3 个功能:

      1. n 个元素的所有组合列表
      2. n 元素列表的所有组合,其中顺序不明确
      3. 所有排列
      import sys
      
      def permutations(a):
          return combinations(a, len(a))
      
      def combinations(a, n):
          if n == 1:
              for x in a:
                  yield [x]
          else:
              for i in range(len(a)):
                  for x in combinations(a[:i] + a[i+1:], n-1):
                      yield [a[i]] + x
      
      def combinationsNoOrder(a, n):
          if n == 1:
              for x in a:
                  yield [x]
          else:
              for i in range(len(a)):
                  for x in combinationsNoOrder(a[:i], n-1):
                      yield [a[i]] + x
          
      if __name__ == "__main__":
          for s in combinations(list(map(int, sys.argv[2:])), int(sys.argv[1])):
              print(s)
      

      【讨论】:

      • 我非常喜欢这个!!!谢谢!!! Python 的组合函数有点奇怪。在数学中,“组合”函数是变体,而“combinationsNoOrder”实际上是组合。我猜这会让那些从数学分支来到 Python 的人感到困惑,就像这次对我所做的那样。无论如何,一个很好的解决方案,非常感谢!
      【解决方案13】:
      from itertools import permutations, combinations
      
      
      features = ['A', 'B', 'C']
      tmp = []
      for i in range(len(features)):
          oc = combinations(features, i + 1)
          for c in oc:
              tmp.append(list(c))
      

      输出

      [
       ['A'],
       ['B'],
       ['C'],
       ['A', 'B'],
       ['A', 'C'],
       ['B', 'C'],
       ['A', 'B', 'C']
      ]
      

      【讨论】:

      • permutations 导入未使用。
      【解决方案14】:

      您还可以使用出色的more_itertools 包中的powerset 函数。

      from more_itertools import powerset
      
      l = [1,2,3]
      list(powerset(l))
      
      # [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
      

      我们还可以验证它是否符合 OP 的要求

      from more_itertools import ilen
      
      assert ilen(powerset(range(15))) == 32_768
      

      【讨论】:

        【解决方案15】:

        下面是一个“标准递归答案”,类似于另一个类似的答案 https://stackoverflow.com/a/23743696/711085 。 (实际上我们不必担心堆栈空间不足,因为我们无法处理所有 N! 个排列。)

        它依次访问每个元素,要么取走它,要么离开它(我们可以从这个算法中直接看到 2^N 基数)。

        def combs(xs, i=0):
            if i==len(xs):
                yield ()
                return
            for c in combs(xs,i+1):
                yield c
                yield c+(xs[i],)
        

        演示:

        >>> list( combs(range(5)) )
        [(), (0,), (1,), (1, 0), (2,), (2, 0), (2, 1), (2, 1, 0), (3,), (3, 0), (3, 1), (3, 1, 0), (3, 2), (3, 2, 0), (3, 2, 1), (3, 2, 1, 0), (4,), (4, 0), (4, 1), (4, 1, 0), (4, 2), (4, 2, 0), (4, 2, 1), (4, 2, 1, 0), (4, 3), (4, 3, 0), (4, 3, 1), (4, 3, 1, 0), (4, 3, 2), (4, 3, 2, 0), (4, 3, 2, 1), (4, 3, 2, 1, 0)]
        
        >>> list(sorted( combs(range(5)), key=len))
        [(), 
         (0,), (1,), (2,), (3,), (4,), 
         (1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3), 
         (2, 1, 0), (3, 1, 0), (3, 2, 0), (3, 2, 1), (4, 1, 0), (4, 2, 0), (4, 2, 1), (4, 3, 0), (4, 3, 1), (4, 3, 2), 
         (3, 2, 1, 0), (4, 2, 1, 0), (4, 3, 1, 0), (4, 3, 2, 0), (4, 3, 2, 1), 
         (4, 3, 2, 1, 0)]
        
        >>> len(set(combs(range(5))))
        32
        

        【讨论】:

          【解决方案16】:

          我知道使用 itertools 获取 所有 组合更为实用,但如果您恰好愿意,可以部分地通过列表理解来实现这一点,授予您大量编写代码

          对于两对的组合:

          lambda l: [(a, b) for i, a in enumerate(l) for b in l[i+1:]]
          

          而且,对于三对的组合,就这么简单:

          lambda l: [(a, b, c) for i, a in enumerate(l) for ii, b in enumerate(l[i+1:]) for c in l[i+ii+2:]]
          

          结果与使用 itertools.combinations 相同:

          import itertools
          combs_3 = lambda l: [
              (a, b, c) for i, a in enumerate(l) 
              for ii, b in enumerate(l[i+1:]) 
              for c in l[i+ii+2:]
          ]
          data = ((1, 2), 5, "a", None)
          print("A:", list(itertools.combinations(data, 3)))
          print("B:", combs_3(data))
          # A: [((1, 2), 5, 'a'), ((1, 2), 5, None), ((1, 2), 'a', None), (5, 'a', None)]
          # B: [((1, 2), 5, 'a'), ((1, 2), 5, None), ((1, 2), 'a', None), (5, 'a', None)]
          

          【讨论】:

            【解决方案17】:

            这里有两个itertools.combinations的实现

            返回列表的方法

            def combinations(lst, depth, start=0, items=[]):
                if depth <= 0:
                    return [items]
                out = []
                for i in range(start, len(lst)):
                    out += combinations(lst, depth - 1, i + 1, items + [lst[i]])
                return out
            

            返回一个生成器

            def combinations(lst, depth, start=0, prepend=[]):
                if depth <= 0:
                    yield prepend
                else:
                    for i in range(start, len(lst)):
                        for c in combinations(lst, depth - 1, i + 1, prepend + [lst[i]]):
                            yield c
            

            请注意,建议为这些对象提供辅助函数,因为 prepend 参数是静态的,不会随着每次调用而改变

            print([c for c in combinations([1, 2, 3, 4], 3)])
            # [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
            
            # get a hold of prepend
            prepend = [c for c in combinations([], -1)][0]
            prepend.append(None)
            
            print([c for c in combinations([1, 2, 3, 4], 3)])
            # [[None, 1, 2, 3], [None, 1, 2, 4], [None, 1, 3, 4], [None, 2, 3, 4]]
            

            这是一个非常肤浅的案例,但最好是安全而不是抱歉

            【讨论】:

              【解决方案18】:

              这个怎么样.. 使用字符串而不是列表,但同样的事情.. 在 Python 中字符串可以被视为列表:

              def comb(s, res):
                  if not s: return
                  res.add(s)
                  for i in range(0, len(s)):
                      t = s[0:i] + s[i + 1:]
                      comb(t, res)
              
              res = set()
              comb('game', res) 
              
              print(res)
              

              【讨论】:

                【解决方案19】:

                如果没有itertools 在 Python 3 中你可以这样做:

                def combinations(arr, carry):
                    for i in range(len(arr)):
                        yield carry + arr[i]
                        yield from combinations(arr[i + 1:], carry + arr[i])
                

                最初在哪里carry = "".

                【讨论】:

                  【解决方案20】:

                  来自 itertools 的组合

                  import itertools
                  col_names = ["aa","bb", "cc", "dd"]
                  all_combinations = itertools.chain(*[itertools.combinations(col_names,i+1) for i,_ in enumerate(col_names)])
                  print(list(all_combinations))
                  

                  【讨论】:

                    【解决方案21】:

                    这段代码使用了一个简单的嵌套列表算法...

                    # FUNCTION getCombos: To generate all combos of an input list, consider the following sets of nested lists...
                    #
                    #           [ [ [] ] ]
                    #           [ [ [] ], [ [A] ] ]
                    #           [ [ [] ], [ [A],[B] ],         [ [A,B] ] ]
                    #           [ [ [] ], [ [A],[B],[C] ],     [ [A,B],[A,C],[B,C] ],                   [ [A,B,C] ] ]
                    #           [ [ [] ], [ [A],[B],[C],[D] ], [ [A,B],[A,C],[B,C],[A,D],[B,D],[C,D] ], [ [A,B,C],[A,B,D],[A,C,D],[B,C,D] ], [ [A,B,C,D] ] ]
                    #
                    #  There is a set of lists for each number of items that will occur in a combo (including an empty set).
                    #  For each additional item, begin at the back of the list by adding an empty list, then taking the set of
                    #  lists in the previous column (e.g., in the last list, for sets of 3 items you take the existing set of
                    #  3-item lists and append to it additional lists created by appending the item (4) to the lists in the
                    #  next smallest item count set. In this case, for the three sets of 2-items in the previous list. Repeat
                    #  for each set of lists back to the initial list containing just the empty list.
                    #
                    
                    def getCombos(listIn = ['A','B','C','D','E','F'] ):
                        listCombos = [ [ [] ] ]     # list of lists of combos, seeded with a list containing only the empty list
                        listSimple = []             # list to contain the final returned list of items (e.g., characters)
                    
                        for item in listIn:
                            listCombos.append([])   # append an emtpy list to the end for each new item added
                            for index in xrange(len(listCombos)-1, 0, -1):  # set the index range to work through the list
                                for listPrev in listCombos[index-1]:        # retrieve the lists from the previous column
                                    listCur = listPrev[:]                   # create a new temporary list object to update
                                    listCur.append(item)                    # add the item to the previous list to make it current
                                    listCombos[index].append(listCur)       # list length and append it to the current list
                    
                                    itemCombo = ''                          # Create a str to concatenate list items into a str
                                    for item in listCur:                    # concatenate the members of the lists to create
                                        itemCombo += item                   # create a string of items
                                    listSimple.append(itemCombo)            # add to the final output list
                    
                        return [listSimple, listCombos]
                    # END getCombos()
                    

                    【讨论】:

                    • 所以这段代码似乎要做的是返回 [listOfCombinations, listOfCombinationsGroupedBySize]。不幸的是,当使用演示输入运行时,它给出了 63 个元素而不是 64 个;它似乎缺少空集(在本例中为空字符串"")。
                    【解决方案22】:

                    不使用 itertools:

                    def combine(inp):
                        return combine_helper(inp, [], [])
                    
                    
                    def combine_helper(inp, temp, ans):
                        for i in range(len(inp)):
                            current = inp[i]
                            remaining = inp[i + 1:]
                            temp.append(current)
                            ans.append(tuple(temp))
                            combine_helper(remaining, temp, ans)
                            temp.pop()
                        return ans
                    
                    
                    print(combine(['a', 'b', 'c', 'd']))
                    

                    【讨论】:

                      【解决方案23】:

                      这是我的实现

                      def get_combinations(list_of_things):
                      """gets every combination of things in a list returned as a list of lists
                      
                      Should be read : add all combinations of a certain size to the end of a list for every possible size in the
                      the list_of_things.
                      
                      """
                      list_of_combinations = [list(combinations_of_a_certain_size)
                                              for possible_size_of_combinations in range(1,  len(list_of_things))
                                              for combinations_of_a_certain_size in itertools.combinations(list_of_things,
                                                                                                           possible_size_of_combinations)]
                      return list_of_combinations
                      

                      【讨论】:

                      • 你的实现比这里发布的以前的实现解决的更好。
                      【解决方案24】:

                      使用列表推导:

                      def selfCombine( list2Combine, length ):
                          listCombined = str( ['list2Combine[i' + str( i ) + ']' for i in range( length )] ).replace( "'", '' ) \
                                           + 'for i0 in range(len( list2Combine ) )'
                          if length > 1:
                              listCombined += str( [' for i' + str( i ) + ' in range( i' + str( i - 1 ) + ', len( list2Combine ) )' for i in range( 1, length )] )\
                                  .replace( "', '", ' ' )\
                                  .replace( "['", '' )\
                                  .replace( "']", '' )
                      
                          listCombined = '[' + listCombined + ']'
                          listCombined = eval( listCombined )
                      
                          return listCombined
                      
                      list2Combine = ['A', 'B', 'C']
                      listCombined = selfCombine( list2Combine, 2 )
                      

                      输出将是:

                      ['A', 'A']
                      ['A', 'B']
                      ['A', 'C']
                      ['B', 'B']
                      ['B', 'C']
                      ['C', 'C']
                      

                      【讨论】:

                      • 这个提议是做字符串修改来建立集合?!?!神圣的乌鸦....并且:它不是返回powerset,而是返回combinations_with_replacement()之类的东西。 (见docs.python.org/library/…
                      • 这确实与 combination_with_replacement() 相同,但至少在我的机器上,它的运行速度比 itertools 稍快。我能说什么,我喜欢列表推导式。
                      • 感谢您的回答!那么创建列表如何结合反向列表,例如 ['A', 'A'], ['A', 'B'], ['A', 'C'], ['B', 'A'], [ 'B', 'B'], ['B', 'C'], ['C', 'A'], ['C', 'B'] 和 ['C', 'C'] 包括一切?
                      • 非常有趣,但我的 python 还不能理解这里的微妙之处。在不同的范围内使用 listCombined 以及 for 循环都在一行中这一事实有什么特别之处吗?我正在尝试将其移植到 Java,但运气不佳。
                      【解决方案25】:

                      我迟到了,但想分享我找到的解决同一问题的方法: 具体来说,我希望进行顺序组合,因此对于“STAR”,我想要“STAR”、“TA”、“AR”,而不是“SR”。

                      lst = [S, T, A, R]
                      lstCombos = []
                      for Length in range(0,len(lst)+1):
                          for i in lst:
                              lstCombos.append(lst[lst.index(i):lst.index(i)+Length])
                      

                      可以通过在最后一行之前添加额外的 if 来过滤重复项:

                      lst = [S, T, A, R]
                      lstCombos = []
                      for Length in range(0,len(lst)+1):
                          for i in lst:
                               if not lst[lst.index(i):lst.index(i)+Length]) in lstCombos:
                                   lstCombos.append(lst[lst.index(i):lst.index(i)+Length])
                      

                      如果由于某种原因这会在输出中返回空白列表,这发生在我身上,我补充说:

                      for subList in lstCombos:
                          if subList = '':
                               lstCombos.remove(subList)
                      

                      【讨论】:

                        【解决方案26】:

                        如果有人正在寻找反向列表,就像我一样:

                        stuff = [1, 2, 3, 4]
                        
                        def reverse(bla, y):
                            for subset in itertools.combinations(bla, len(bla)-y):
                                print list(subset)
                            if y != len(bla):
                                y += 1
                                reverse(bla, y)
                        
                        reverse(stuff, 1)
                        

                        【讨论】:

                          【解决方案27】:
                          flag = 0
                          requiredCals =12
                          from itertools import chain, combinations
                          
                          def powerset(iterable):
                              s = list(iterable)  # allows duplicate elements
                              return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
                          
                          stuff = [2,9,5,1,6]
                          for i, combo in enumerate(powerset(stuff), 1):
                              if(len(combo)>0):
                                  #print(combo , sum(combo))
                                  if(sum(combo)== requiredCals):
                                      flag = 1
                                      break
                          if(flag==1):
                              print('True')
                          else:
                              print('else')
                          
                          

                          【讨论】:

                            【解决方案28】:

                            the documentation中所述

                            def combinations(iterable, r):
                                # combinations('ABCD', 2) --> AB AC AD BC BD CD
                                # combinations(range(4), 3) --> 012 013 023 123
                                pool = tuple(iterable)
                                n = len(pool)
                                if r > n:
                                    return
                                indices = list(range(r))
                                yield tuple(pool[i] for i in indices)
                                while True:
                                    for i in reversed(range(r)):
                                        if indices[i] != i + n - r:
                                            break
                                    else:
                                        return
                                    indices[i] += 1
                                    for j in range(i+1, r):
                                        indices[j] = indices[j-1] + 1
                                    yield tuple(pool[i] for i in indices)
                            
                            
                            x = [2, 3, 4, 5, 1, 6, 4, 7, 8, 3, 9]
                            for i in combinations(x, 2):
                                print i
                            

                            【讨论】:

                            • 如果我是对的,这是从 python 文档 [docs.python.org/3.6/library/itertools.html] 复制的确切代码。如果是这样,请参考来源。
                            • 有趣的方法
                            • @GabrielChu 刚刚修复了它。格式也不正确。
                            【解决方案29】:

                            如果你不想使用组合库,这里是解决方案:

                            nums = [1,2,3]
                            p = [[]]
                            fnl = [[],nums]
                            
                            for i in range(len(nums)):
                                for j in range(i+1,len(nums)):
                                    p[-1].append([i,j])
                            
                            for i in range(len(nums)-3):
                                p.append([])
                                for m in p[-2]:
                                    p[-1].append(m+[m[-1]+1])
                            
                            for i in p:
                                for j in i:
                                    n = []
                                    for m in j:
                                        if m < len(nums):
                                            n.append(nums[m])
                                    if n not in fnl:
                                        fnl.append(n)
                            
                            for i in nums:
                                if [i] not in fnl:
                                    fnl.append([i])
                            
                            print(fnl)
                            

                            输出:

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

                            【讨论】:

                              【解决方案30】:

                              在组合大小上递归的另一种解决方案:

                              def _comb(items, i, res, pos):
                                  if len(items) == i:
                                      return
                              
                                  res += [r + [c] for c in items for r in res[pos:]]
                                  # Combinations are like a tree, and "pos" is the leaves index
                                  # where we build the new sub tree 
                                  _comb(items,i+1, res, len(items)**i+pos)
                              
                              def comb(items):
                                  l = [[]]
                                  _comb(items, 0, l, 0)
                                  return l
                              

                              【讨论】:

                              • 如果您要定义一个函数,请缩进您的代码。
                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2023-02-14
                              • 1970-01-01
                              • 2012-10-18
                              相关资源
                              最近更新 更多