代码之家  ›  专栏  ›  技术社区  ›  Ben

如何获得列表元素的所有可能组合?

  •  304
  • Ben  · 技术社区  · 17 年前

    我找到了 some code

    有人知道更好的方法吗?使用 map() 大概

    24 回复  |  直到 9 年前
        1
  •  716
  •   Steven C. Howell amirhosein majidi    8 年前

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

    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)
    
        2
  •  594
  •   James Brady    17 年前

    itertools.combinations

    itertools.combinations(iterable, r)
    

    从返回元素的r长度子序列 输入不可编辑。

    组合按字典排序顺序发出。那么,如果 组合元组将在中生成

    从2.6开始,电池就包括在内了!

        3
  •  58
  •   Greg    7 年前

    这是一个懒惰的单行程序,也使用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
    

    需要考虑的事项:

    • len(...) 在…上 items (解决方法:如果 是一个类似iterable的东西,就像一个生成器一样,首先用 items=list(_itemsArg) )
    • 这要求迭代的顺序为 不是随机的(解决方法:不要疯了)
    • 这要求项目是唯一的,否则 {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
  •  53
  •   martineau    7 年前

    在高投票率下的评论中 answer powerset() 菜谱 itertools documentation 包括一个接一个 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)
    
        5
  •  41
  •   darxtrix    12 年前

    下面是一个使用递归的例子:

    >>> 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']
    
        6
  •  41
  •   Mathieu Rodic    7 年前

    这一行提供了所有的组合(在 0 n 如果原始列表/集合包含 不同元素)并使用本机方法 itertools.combinations :

    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

        7
  •  35
  •   Jonathan R    7 年前

    这是一种可以很容易地转移到所有支持递归的编程语言的方法 (无itertools,无收益,无列表理解) :

    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]]
    
        8
  •  24
  •   sahinakkaya    5 年前

    您可以使用以下简单代码在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)]
    
        9
  •  22
  •   HongboZhu    14 年前

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

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

    iterable = range(10)
    for s in xrange(len(iterable)+1):
      for comb in itertools.combinations(iterable, s):
        yield comb
    
        10
  •  17
  •   user3078690 user3078690    9 年前

    我想我会为那些寻求答案的人添加这个函数,而不必导入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,

        11
  •  9
  •   ninjagecko    10 年前

    下面是另一个解决方案(一个班轮),涉及使用 itertools.combinations 函数,但这里我们使用双列表理解(与for循环或sum相反):

    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
  •  8
  •   Andrew Li    6 年前
    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']
    ]
    
        13
  •  8
  •   sahinakkaya    5 年前

    1. n个元素的所有组合列表
    2. n个元素的所有组合都会列出顺序不明确的元素
    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)
    
        14
  •  7
  •   Jarno Martin Buberl    6 年前

    您也可以使用 powerset more_itertools 包裹

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

    from more_itertools import ilen
    
    assert ilen(powerset(range(15))) == 32_768
    
        15
  •  4
  •   Community Mohan Dere    9 年前

    下面是一个“标准递归答案”,与其他类似答案类似 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
  •  4
  •   Tiago Peres damanpreet singh    5 年前

    全部的 可以 如果您希望编写代码,那么只需理解列表就可以部分实现这一点

    对于两对的组合:

    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.compositions相同:

    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
  •  3
  •   Modar    8 年前

    下面是 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
    

    请注意,建议为这些函数提供一个helper函数,因为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
  •  3
  •   Apurva Singh    8 年前

    这个怎么样。。使用了字符串而不是列表,但事情是一样的。。字符串可以像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
  •  3
  •   sahinakkaya    5 年前

    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))
    
        20
  •  2
  •   Mattia Maestrini    11 年前

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

    # 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()
    
        21
  •  2
  •   Pradeep Vairamani    8 年前

    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']))
    
        22
  •  2
  •   Laurynas Tamulevičius    7 年前

    没有 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 = "".

        23
  •  2
  •   Tiago Peres damanpreet singh    5 年前

    这是我的实现

    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
  •  1
  •   zmk    14 年前

    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']
    
        25
  •  1
  •   yip_yip    5 年前

    我参加聚会迟到了,但我想分享我发现的解决同一问题的方法: 具体来说,我想做顺序组合,所以对于“星”,我想要“星”、“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])
    

    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
  •  0
  •   Tiago Peres damanpreet singh    5 年前

    如中所述 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
    
        27
  •  0
  •   bhargav3vedi    4 年前

    如果您不想使用组合库,以下是解决方案:

    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]]
    
        28
  •  -1
  •   Cdl    8 年前

    如果有人在寻找一个相反的列表,比如我:

    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)
    
        29
  •  -1
  •   Priyansh gupta    6 年前
    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')