Python combinations without repetition

I have a list of numbers, and I want to make combinations from it. If I have a list:

t = [2,2,2,2,4] c = list(itertools.combinations(t, 4)) 

Result:

 (2, 2, 2, 2) (2, 2, 2, 4) (2, 2, 2, 4) (2, 2, 2, 4) (2, 2, 2, 4) 

but I want to get:

 (2, 2, 2, 2) (2, 2, 2, 4) 

Is it possible to exclude duplicates, except creating a new list and going through the first list?

+8
python
source share
3 answers

As Donkey Kong points out, you can get unique values ​​in a list by translating the list into a set:

 t = [2,2,2,2,4] c = list(itertools.combinations(t, 4)) unq = set(c) print(unq) 

And the result will be:

 {(2, 2, 2, 4), (2, 2, 2, 2)} 

If you want to use it as a list, you can convert it by doing:

 result = list(unq) 

An alternative and cleaner, more comprehensive way would be:

 t = [2,2,2,2,4] c = set(itertools.combinations(t, 4)) 
+5
source share

I know it's late, but I want to add an item.

set(itertools.combinations(t, 4)) excellent set(itertools.combinations(t, 4)) for most cases, but still internally repeats all repeated combinations, so it can be computationally difficult. This is especially true if there are not many actual unique combinations.

This repeats only unique combinations:

 from itertools import chain,repeat,islice,count from collections import Counter def combinations_without_repetition(r, iterable=None, values=None, counts=None): if iterable: values, counts = zip(*Counter(iterable).items()) f = lambda i,c: chain.from_iterable(map(repeat, i, c)) n = len(counts) indices = list(islice(f(count(),counts), r)) if len(indices) < r: return while True: print(indices) yield tuple(values[i] for i in indices) for i,j in zip(reversed(range(r)), f(reversed(range(n)), reversed(counts))): if indices[i] != j: break else: return j = indices[i]+1 for i,j in zip(range(i,r), f(count(j), islice(counts, j, None))): indices[i] = j 

Using:

 >>> t = [2,2,2,2,4] # elements in t must be hashable >>> list(combinations_without_repetition(4, iterable=t)) [(2, 2, 2, 2), (2, 2, 2, 4)] # You can pass values and counts separately. For this usage, values don't need to be hashable # Say you have ['a','b','b','c','c','c'], then since there is 1 of 'a', 2 of 'b', and 3 of 'c', you can do as follows: >>> list(combinations_without_repetition(3, values=['a','b','c'], counts=[1,2,3])) [('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'c'), ('b', 'b', 'c'), ('b', 'c', 'c'), ('c', 'c', 'c')] # combinations_without_repetition() is a generator (and thus an iterator) # so you can iterate it >>> for comb in combinations_without_repetition(4, t): ... print(sum(comb)) ... 8 # 2+2+2+2 10 # 2+2+2+4 

Please note that itertools.combinations() implemented in C, which means that in most cases it works much faster than my python script. This code works better than the set(itertools.combinations()) method only when there are set(itertools.combinations()) MORE duplicate combinations than unique combinations.

+7
source share

Technically, what you get doesn’t actually duplicate, just how itertools.combinations works if you read the description on the linked page:

itertools.combinations(iterable, r)

Returns r subsequences of elements from an input iterable.

Combinations are emitted in lexicographic sorting order. So, if the sorting of the input iterator is sorted, combinational tuples will be created in sorted order.

Elements are considered unique, based on their position, and not on their value . Therefore, if the input elements are unique, do not repeat the values ​​in each combination.

DEMO:

 >>> import itertools as it >>> list(it.combinations([1,2,3,4,5], 4)) [(1, 2, 3, 4), (1, 2, 3, 5), (1, 2, 4, 5), (1, 3, 4, 5), (2, 3, 4, 5)] 

So, as in the previous answer, set() will give you unique values:

 >>> set(it.combinations(t, 4)) {(2, 2, 2, 4), (2, 2, 2, 2)} 
+5
source share

All Articles