我将如何以最快的方式计算元素数组的排列,每个排列在排列内重复一定次数?
例如:
elements = [0, 1]
repetitions = [2, 3]
我希望它返回10个唯一的排列:
[(0, 0, 1, 1, 1), (0, 1, 0, 1, 1), (1, 0, 1, 0, 1) ....]
答案 0 :(得分:1)
这是一个解决方案:想法是找到所有可能的索引,我们可以将第一个元素放在这里,然后递归地找到其余索引的可能索引。这样,我们可以保证直接生成唯一的输出。
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)
答案 1 :(得分:0)
这不是一个完整的答案,而是总体思路。 我几乎可以肯定,没有递归和组合(itertools),没有简单的方法可以做到这一点。 假设您已经定义了数据,元素和重复项。
我猜您必须进行一次递归,这将转化为递归函数。 En是元素数组。 Rn是重复数组。 因此,En-1是n-1个第一元素和Rn-1个第一元素的数组。 如果您知道En-1和Rn-1的解决方案,则只需计算与itertools软件包see here的组合。 以您的示例为例,您知道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
很抱歉,没有时间编写完整的解决方案。 我猜这更多是数学问题,而不是代码问题。
使用下面的Erwan的想法,也许这段代码可以工作:
from itertools import permutations
n = len(elements)
repeated_elements_array = [element[i]*repetition[i] for i in range(n)]
repeated_elements_list = []
for repeated_elements in repeated_elements_array:
repeated_elements_list += repeated_elements
s = 0
for repetition in repetitions:
s += repetition
solution = permutations(repeated_elements_list, s)
答案 2 :(得分:0)
您可以从permutations
模块使用itertools
>>> 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可能出现多次),请查看here
Edit2:如果元素中只有0.1,并且不想重复,则可以使用类似(j for j in ([i%2, i//2%2, i//4%2, i//8%2, i//16%2] for i in range(0, 2**5)) if sum(j)==3)
的二进制表示形式。我不知道它是否更快。
答案 3 :(得分:0)
类似于@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)))