如何计算具有重复元素的列表的排列(排列)

时间:2018-10-17 11:46:29

标签: python math combinations permutation

我有一个包含重复元素的列表,即orig = [1,1,1,2,2,3]
我想创建一个derangement b = f(orig),以使b中的每个位置值都与orig中的值不同:

b[i] != orig[i], for all i 

orig中的所有元素都是唯一的时,我知道一种解决方案,但这是更困难的情况。

使用python开发解决方案,但是任何语言都可以。

2 个答案:

答案 0 :(得分:1)

效率不高的解决方案显然是

import itertools
set([s for s in itertools.permutations(orig) if not any([a == b for a, b in zip(s, orig)])])

第二种方法和第一种改进是使用this perm_unique

 [s for s in perm_unique(orig) if not any([a == b for a, b in zip(s, orig)])]

第三种方法是使用此超级快速unique_permutations algorithm

 import copy
 [copy.copy(s) for s in unique_permutations(orig) if not any([a == b for a, b in zip(s, orig)])]

在装有%%timeit的笔记本中,初始方法为841 µs,然后我们改进为266 µs,然后改进为137 µs

修改

不能停止考虑,对第二种方法进行了少量编辑。没有时间去研究最后一种方法。有关说明,请先参阅原始帖子(上面的链接)。然后,我仅添加了强制执行混乱状态的检查and el != elements[depth]。这样,我们得出的运行时间为50 µs

from collections import Counter

def derangement_unique(elements):
    list_unique = Counter(elements)
    length_list = len(elements)  # will become depth in the next function
    placeholder = [0]*length_list  # will contain the result
    return derangement_unique_helper(elements, list_unique, placeholder, length_list-1)

def derangement_unique_helper(elements, list_unique, result_list, depth):
    if depth < 0:   # arrived at a solution
        yield tuple(result_list)
    else:
        # consider all elements and how many times they should still occur 
        for el, count in list_unique.items():
            # ... still required and not breaking the derangement requirement
            if count > 0 and el != elements[depth]:   
                result_list[depth] = el  # assignment element
                list_unique[el] -= 1   # substract number needed
                # loop for all possible continuations 
                for g in derangement_unique_helper(elements, list_unique, result_list, depth-1):
                    yield g
                list_unique[el] += 1


list(derangement_unique(orig))

答案 1 :(得分:0)

如果您的列表中包含大量重复项,则可能很难快速找到乱序。

在这种情况下,您可以尝试图形方法。

处理初始列表以创建一个图形,其中每个项目都与不相等的元素相连(易于排序的列表)。

然后构建完美匹配(如果元素数量为偶数)或接近完美的匹配(对于奇数,这里您需要找到一些合适的对并将单个节点加入其中)。

匹配的边缘表示交换以进行重新排列。

Python库networkx应该包含所需的方法。