How to get all possible combinations of a list’s elements?
我有一个包含15个数字的列表,我需要编写一些代码来生成这些数字的所有32768个组合。
我发现了一些代码(通过谷歌搜索),它们显然可以满足我的需求,但是我发现代码相当不透明,并且对使用它很谨慎。另外,我觉得必须有一个更优雅的解决方案。
对我来说,唯一发生的事情就是循环遍历十进制整数1–32768,然后将其转换为二进制,并使用二进制表示作为过滤器来选择合适的数字。
有人知道更好的方法吗?可能使用
这个答案遗漏了一个方面:操作要求所有组合…不仅仅是长度"r"的组合。
所以你要么把所有长度的"L"都圈起来:
1 2 3 4 5 6 | import itertools stuff = [1, 2, 3] for L in range(0, len(stuff)+1): for subset in itertools.combinations(stuff, L): print(subset) |
或者——如果你想变得时髦(或者让在你之后阅读你的代码的人的大脑弯曲)——你可以生成"combinations()"生成器链,然后迭代:
1 2 3 4 5 6 | 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) |
看看itertools.combinations:
1 itertools.combinations(iterable, r)Return r length subsequences of elements from
the input iterable.Combinations are emitted in lexicographic sort order. So, if the
input iterable is sorted, the
combination tuples will be produced in
sorted order.
从2.6开始,电池就包括在内!
这里有一个懒惰的一行程序,也使用itertools:
1 2 3 4 5 | 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"对应的所有元素。
1 2 3 4 5 6 7 8 9 10 11 | 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())) ,如果您需要它是可哈希的)
演示
1 2 3 4 5 | >>> 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'}] |
在@dan h高度乐观的回答下的评论中,提到了
注:如果目标是仅获得唯一元素的组合,则将行
1 2 3 4 5 6 7 8 9 10 | 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)) |
输出:
1 2 3 4 5 6 7 8 | 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) |
下面是一个使用递归的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | >>> 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'] |
如果原始列表/集合中包含
1 2 3 4 5 | 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
1 2 3 4 5 | from itertools import combinations input = ['a', 'b', 'c', 'd'] output = sum([list(map(list, combinations(input, i))) for i in range(len(input) + 1)], []) |
输出将是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [[], ['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
我同意丹H的观点,本确实要求所有的组合。
另一个问题是,如果输入iterable很大,那么最好返回一个生成器,而不是列表中的所有内容:
1 2 3 4 | iterable = range(10) for s in xrange(len(iterable)+1): for comb in itertools.combinations(iterable, s): yield comb |
您可以使用这个简单的代码在python中生成列表的所有组合
1 2 3 4 5 | 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 5 | [()] [(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)] |
我想我应该为那些在不导入itertools或任何其他额外库的情况下寻求答案的用户添加这个函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 |
简单的产量发生器用途:
1 2 | 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] ,
这里还有另一个解决方案(一行程序),涉及使用
1 2 | def combs(x): return [c for i in range(len(x)+1) for c in combinations(x,i)] |
演示:
1 2 3 4 5 6 | >>> 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)] |
它可以用itertools来完成。
对于排列
此方法将列表作为输入,并返回以列表形式包含长度l排列的元组的对象列表。
1 2 3 4 5 6 7 8 9 10 11 | # A Python program to print all # permutations of given length from itertools import permutations # Get all permutations of length 2 # and length 2 perm = permutations([1, 2, 3], 2) # Print the obtained permutations for i in list(perm): print (i) |
结合使用
此方法将一个列表和一个输入r作为输入,并返回一个包含列表形式中所有可能长度r组合的元组的对象列表。
1 2 3 4 5 6 7 8 9 10 11 | # A Python program to print all # combinations of given length from itertools import combinations # Get all combinations of [1, 2, 3] # and length 2 comb = combinations([1, 2, 3], 2) # Print the obtained combinations for i in list(comb): print (i) |
看到这个
下面是一个"标准递归答案",类似于其他类似的答案https://stackoverflow.com/a/23743696/711085。(实际上,我们不必担心耗尽堆栈空间,因为我们无法处理所有n!排列。
它依次访问每一个元素,要么接受它,要么离开它(我们可以直接从这个算法中看到2^n的基数)。
1 2 3 4 5 6 7 | def combs(xs, i=0): if i==len(xs): yield () return for c in combs(xs,i+1): yield c yield c+(xs[i],) |
演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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 |
这是一种可以轻松地传输到所有支持递归的编程语言的方法(没有itertools,没有yield,没有清单理解):
1 2 3 4 5 6 7 8 9 10 | 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]] |
我知道使用itertools获得所有的组合要实际得多,但是如果你希望这样做的话,如果你想编写很多代码的话,你只需要理解列表就可以实现这一点。
对于两对组合:
1 | lambda l: [(a, b) for i, a in enumerate(l) for b in l[i+1:]] |
< BR>而且,对于三对组合,就这么简单:
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相同:
1 2 3 4 5 6 7 8 9 10 11 | 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)] |
不使用itertools:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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'])) |
这段代码使用了一个简单的嵌套列表算法…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # 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() |
这个怎么样……使用了字符串而不是列表,但相同的是..字符串可以像python中的列表一样处理:
1 2 3 4 5 6 7 8 9 10 11 | 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) |
来自Itertools的组合
1 2 3 4 | 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)) |
谢谢
如果没有Python3中的
1 2 3 4 | def combinations(arr, carry): for i in range(len(arr)): yield carry + arr[i] yield from combinations(arr[i + 1:], carry + arr[i]) |
其中,最初的
这是我的实现
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
下面是
返回列表的
1 2 3 4 5 6 7 | 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 |
一个返回一个生成器
1 2 3 4 5 6 7 | 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参数是静态的,不会随每个调用而更改。
1 2 3 4 5 6 7 8 9 | 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]] |
这是一个很肤浅的情况,但最好安全些,不要后悔。
使用列表理解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 ) |
输出为:
1 2 3 4 5 6 | ['A', 'A'] ['A', 'B'] ['A', 'C'] ['B', 'B'] ['B', 'C'] ['C', 'C'] |
如果有人在找一个颠倒的名单,就像我一样:
1 2 3 4 5 6 7 8 9 10 | 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) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 = 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 |