permutations with unique values

前端 未结 19 1450
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-22 01:53

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:

相关标签:
19条回答
  • 2020-11-22 02:23

    Bumped into this question while looking for something myself !

    Here's what I did:

    def dont_repeat(x=[0,1,1,2]): # Pass a list
        from itertools import permutations as per
        uniq_set = set()
        for byt_grp in per(x, 4):
            if byt_grp not in uniq_set:
                yield byt_grp
                uniq_set.update([byt_grp])
        print uniq_set
    
    for i in dont_repeat(): print i
    (0, 1, 1, 2)
    (0, 1, 2, 1)
    (0, 2, 1, 1)
    (1, 0, 1, 2)
    (1, 0, 2, 1)
    (1, 1, 0, 2)
    (1, 1, 2, 0)
    (1, 2, 0, 1)
    (1, 2, 1, 0)
    (2, 0, 1, 1)
    (2, 1, 0, 1)
    (2, 1, 1, 0)
    set([(0, 1, 1, 2), (1, 0, 1, 2), (2, 1, 0, 1), (1, 2, 0, 1), (0, 1, 2, 1), (0, 2, 1, 1), (1, 1, 2, 0), (1, 2, 1, 0), (2, 1, 1, 0), (1, 0, 2, 1), (2, 0, 1, 1), (1, 1, 0, 2)])
    

    Basically, make a set and keep adding to it. Better than making lists etc. that take too much memory.. Hope it helps the next person looking out :-) Comment out the set 'update' in the function to see the difference.

    0 讨论(0)
  • 2020-11-22 02:23

    Came across this the other day while working on a problem of my own. I like Luka Rahne's approach, but I thought that using the Counter class in the collections library seemed like a modest improvement. Here's my code:

    def unique_permutations(elements):
        "Returns a list of lists; each sublist is a unique permutations of elements."
        ctr = collections.Counter(elements)
    
        # Base case with one element: just return the element
        if len(ctr.keys())==1 and ctr[ctr.keys()[0]] == 1:
            return [[ctr.keys()[0]]]
    
        perms = []
    
        # For each counter key, find the unique permutations of the set with
        # one member of that key removed, and append the key to the front of
        # each of those permutations.
        for k in ctr.keys():
            ctr_k = ctr.copy()
            ctr_k[k] -= 1
            if ctr_k[k]==0: 
                ctr_k.pop(k)
            perms_k = [[k] + p for p in unique_permutations(ctr_k)]
            perms.extend(perms_k)
    
        return perms
    

    This code returns each permutation as a list. If you feed it a string, it'll give you a list of permutations where each one is a list of characters. If you want the output as a list of strings instead (for example, if you're a terrible person and you want to abuse my code to help you cheat in Scrabble), just do the following:

    [''.join(perm) for perm in unique_permutations('abunchofletters')]
    
    0 讨论(0)
  • 2020-11-22 02:24

    Here is a recursive solution to the problem.

    def permutation(num_array):
        res=[]
        if len(num_array) <= 1:
            return [num_array]
        for num in set(num_array):
            temp_array = num_array.copy()
            temp_array.remove(num)
            res += [[num] + perm for perm in permutation(temp_array)]
        return res
    
    arr=[1,2,2]
    print(permutation(arr))
    
    0 讨论(0)
  • 2020-11-22 02:24

    I came up with a very suitable implementation using itertools.product in this case (this is an implementation where you want all combinations

    unique_perm_list = [''.join(p) for p in itertools.product(['0', '1'], repeat = X) if ''.join(p).count() == somenumber]
    

    this is essentially a combination (n over k) with n = X and somenumber = k itertools.product() iterates from k = 0 to k = X subsequent filtering with count ensures that just the permutations with the right number of ones are cast into a list. you can easily see that it works when you calculate n over k and compare it to the len(unique_perm_list)

    0 讨论(0)
  • 2020-11-22 02:26
    ans=[]
    def fn(a, size): 
        if (size == 1): 
            if a.copy() not in ans:
                ans.append(a.copy())
                return
    
        for i in range(size): 
            fn(a,size-1); 
            if size&1: 
                a[0], a[size-1] = a[size-1],a[0] 
            else: 
                a[i], a[size-1] = a[size-1],a[i]
    

    https://www.geeksforgeeks.org/heaps-algorithm-for-generating-permutations/

    0 讨论(0)
  • 2020-11-22 02:28

    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,3
    • Let's iterate through them: first_element starts with 1.
      • remaining_elements are [2,3,1] (ie. 1,2,3,1 minus the first 1)
      • We iterate (recursively) through the permutations of the remaining elements: (1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)
      • For each sub_permutation, we insert the first_element: (1,1,2,3), (1,1,3,2), ... and yield the result.
    • Now we iterate to first_element = 2, and do the same as above.
      • remaining_elements are [1,3,1] (ie. 1,2,3,1 minus the first 2)
      • We iterate through the permutations of the remaining elements: (1, 1, 3), (1, 3, 1), (3, 1, 1)
      • For each sub_permutation, we insert the first_element: (2, 1, 1, 3), (2, 1, 3, 1), (2, 3, 1, 1)... and yield the result.
    • Finally, we do the same with first_element = 3.
    0 讨论(0)
提交回复
热议问题