def ref_permutations(iterable, r=None):
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = list(range(n))
cycles = list(range(n, n-r, -1))
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return
它已经比实际的itertools.permutations慢了40倍。 如果你有每个元素的频率列表,比如n = list(collections.Counter(x).values()),multiset_permutations的复杂度是O(factorial(sum(n)) / prod(factorial(ni) for ni in n)),而排列是O(factorial(sum(n)),如果sum(1 for _ in itertools.product(x)) / sum(1 for _ in multiset_permutations(x)) > 100,那么multiset_permutations应该更快。 但要注意的是,它的复杂性至少是不同元素数量的阶乘。如果达到15,你就有大麻烦了。
1条答案
按热度按时间4ioopgfo1#
检查sympy 1.11 multiset_permutations的源代码。
我们可以看到,如果你有所有唯一的元素,它产生的排列从itertools导入。
因此,对于这种情况,复杂性是相同的,但
multiset_permutations
会增加开销。如果我们以
abcdegfhij
的排列为例,itertools.permutations
需要约300ms,multiset_permutations
需要约700ms。然而
permutations
做了更多的工作,从文档中获取参考实现。它已经比实际的
itertools.permutations
慢了40倍。如果你有每个元素的频率列表,比如
n = list(collections.Counter(x).values())
,multiset_permutations
的复杂度是O(factorial(sum(n)) / prod(factorial(ni) for ni in n))
,而排列是O(factorial(sum(n))
,如果sum(1 for _ in itertools.product(x)) / sum(1 for _ in multiset_permutations(x)) > 100
,那么multiset_permutations
应该更快。但要注意的是,它的复杂性至少是不同元素数量的阶乘。如果达到15,你就有大麻烦了。