具有特定重复的元素数组的Python置换

具有特定重复的元素数组的Python置换,python,combinations,permutation,Python,Combinations,Permutation,如何以最快的方式计算元素数组的排列,每个元素在排列中重复一定次数 例如: elements = [0, 1] repetitions = [2, 3] 我希望它返回10个唯一的排列: [(0, 0, 1, 1, 1), (0, 1, 0, 1, 1), (1, 0, 1, 0, 1) ....] 这不是一个完整的答案,而是总体思路。 我几乎可以肯定,没有递归和组合(itertools),没有简单的方法可以做到这一点。 假设您已经定义了数据、元素和重复 n是元素的大小 s是所有重复项的总和,

如何以最快的方式计算元素数组的排列,每个元素在排列中重复一定次数

例如:

elements = [0, 1]
repetitions = [2, 3]
我希望它返回10个唯一的排列:

[(0, 0, 1, 1, 1), (0, 1, 0, 1, 1), (1, 0, 1, 0, 1) ....]

这不是一个完整的答案,而是总体思路。 我几乎可以肯定,没有递归和组合(itertools),没有简单的方法可以做到这一点。 假设您已经定义了数据、元素和重复

  • n是元素的大小
  • s是所有重复项的总和, 所以它是每个排列的最终元素数 寻找
我想,你必须进行一次递归,这将转化为一个递归函数。 En是元素数组。 Rn是重复的数组。 因此En-1是n-1个第一元素和Rn-1个第一元素的数组。 如果您知道En-1和Rn-1的解决方案,只需计算与itertools包的组合即可。 以你的例子来说,你知道E2和R2,对吗? 我会尽量找时间写代码,我不知道你对递归性有多熟悉,这可能很难理解

from itertools import combinations

def multipleElementsPermutations(elements, repetitions): #elements is En, repetitions is Rn
    if len(elements) != len(repetitions) or len(elements) <2 or len(repetitions) <2:
        return None 
    elif len(elements) == 2:
        #Write some code using itertools to solve the case n=2
        return list(permutations(elements[0]*repetitions[0] + elements[1]*repetitions[1], repetitions[0]+repetitions[1]))
    else:
        last_element = elements[-1]
        last_repetition = repetitions[-1]
        #Here thus function will call itself with the n-1 arguments
        previous_case_solution = multipleElementsPermutation(
            elements[:-1], #En-1
            repetitions[:-1] #Rn-1
        )
        #Write some code here to find different ways to add last element

您可以使用
itertools
模块中的
permutations

>>> from itertools import permutations
>>> list(permutations([0]*2 + [1]*3, 5))
[(0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0)]
更自动的版本:

>>> e = [0, 1]
>>> r = [2, 3]
>>> b = sum([[i]*j for i, j in zip(e, r)], [])
>>> list(permutations(b, len(b)))
[(0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 0, 1, 1, 1), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 0, 1, 1), (0, 1, 0, 1, 1), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1), (0, 1, 1, 1, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 0, 1, 1), (1, 0, 0, 1, 1), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 1, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 0, 0, 1), (1, 1, 0, 1, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0)]
编辑:如@JosephWood所述,如果您不想重复(00111可能出现多次),请查看


Edit2:如果元素中只有0,1,并且不希望重复,那么如果和(j)==3,则可以使用这样的二进制表示法
(j表示j in([i%2,i//2%2,i//4%2,i//8%2,i//16%2])。我不知道它是否更快。

类似于@Erwan,它也可以工作:

import itertools as it
elements = [0, 1]
repetitions = [2, 3]
arr = []
for j,i in enumerate(repetitions):
   arr = arr +[elements[j]]*i

set(list(it.permutations(arr)))

这里有一个解决方案:想法是找到所有可能的索引,我们可以把第一个元素,然后递归地找到可能的索引为其余的。这样,我们就可以保证直接生成唯一的输出

from itertools import combinations


def combs(elements, repetitions, index=0, indices_left=None, already_set=None):
    if indices_left is None:
        already_set = [None] * sum(repetitions)
        indices_left = set(range(sum(repetitions)))

    element = elements[index]
    number = repetitions[index]

    for indices_choice in combinations(indices_left, number):
        currently_set = already_set[:]
        for i in indices_choice:
            currently_set[i] = element
        remaining_indices = indices_left - set(indices_choice)
        if not remaining_indices:
            yield currently_set
        else:
            yield from combs(elements, repetitions, index+1, remaining_indices, currently_set)
通过您的示例输入,我们可以:

elements = [0, 1]
repetitions = [2, 3]

for comb in combs(elements, repetitions):
    print(comb)

# [0, 0, 1, 1, 1]
# [0, 1, 0, 1, 1]
# [0, 1, 1, 0, 1]
# [0, 1, 1, 1, 0]
# [1, 0, 0, 1, 1]
# [1, 0, 1, 0, 1]
# [1, 0, 1, 1, 0]
# [1, 1, 0, 0, 1]
# [1, 1, 0, 1, 0]
# [1, 1, 1, 0, 0]
另一个包含更多元素的示例:

elements = [0, 1, 2]
repetitions = [2, 3, 2]

c = combs(elements, repetitions)

print(next(c))
# [0, 0, 1, 1, 1, 2, 2]

print(next(c))
# [0, 0, 1, 1, 2, 1, 2]

print(len(list(combs(elements, repetitions))))
# 210
一点速度测试:

elements = [0, 1]
repetitions = [10, 10]

a = list(combs(elements, repetitions))
print(len(a))
# 184756

%timeit list(combs(elements, repetitions))
# 1.15 s ± 5.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

很好,也许我们可以找到元素的解决方案。你的元素向量中只有0和1,或者你想要任何随机整数吗?这些被称为多重集,可以通过
sympy
multiset\u置换生成。这段代码生成120个元组,虽然只有10个不同的输出。@Thierrylahuille更正。谢谢。但问题是,在开始使用
set()
删除重复项之前,您的代码需要生成大量相同的排列,所有排列都存储在内存中。这将很快变得不正式:例如,对于
重复=[10,10]
,您需要生成一个包含2432902008176640000(2.4e18)项的列表,这是不可能的,因为需要时间和空间,而只有184756个唯一的排列。
elements = [0, 1]
repetitions = [10, 10]

a = list(combs(elements, repetitions))
print(len(a))
# 184756

%timeit list(combs(elements, repetitions))
# 1.15 s ± 5.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)