itertools.permutations generates where its elements are treated as unique based on their position, not on their value. So basically I want to avoid duplicates like this:
Roughly as fast as Luka Rahne's answer, but shorter & simpler, IMHO.
def unique_permutations(elements):
if len(elements) == 1:
yield (elements[0],)
else:
unique_elements = set(elements)
for first_element in unique_elements:
remaining_elements = list(elements)
remaining_elements.remove(first_element)
for sub_permutation in unique_permutations(remaining_elements):
yield (first_element,) + sub_permutation
>>> list(unique_permutations((1,2,3,1)))
[(1, 1, 2, 3), (1, 1, 3, 2), (1, 2, 1, 3), ... , (3, 1, 2, 1), (3, 2, 1, 1)]
It works recursively by setting the first element (iterating through all unique elements), and iterating through the permutations for all remaining elements.
Let's go through the unique_permutations
of (1,2,3,1) to see how it works:
unique_elements
are 1,2,3first_element
starts with 1.
remaining_elements
are [2,3,1] (ie. 1,2,3,1 minus the first 1)sub_permutation
, we insert the first_element
: (1,1,2,3), (1,1,3,2), ... and yield the result.first_element
= 2, and do the same as above.
remaining_elements
are [1,3,1] (ie. 1,2,3,1 minus the first 2)sub_permutation
, we insert the first_element
: (2, 1, 1, 3), (2, 1, 3, 1), (2, 3, 1, 1)... and yield the result.first_element
= 3.