How to calculate this number instead of enumerate all permutations and then create set to cut off all repetitions?
len(set(itertools.permutations('aaabbb')))
20
len(set(itertools.permutations('aabb')))
6
Let counts be an array with counts[k] = count of the k'th symbol.
We'll need a way for python to easily compute a bunch of multiplications, a product() function....
From What's the Python function like sum() but for multiplication? product()?:
from functools import reduce # Valid in Python 2.6+, required in Python 3
import operator
def product(X):
return reduce(operator.mul, X, 1)
Now we can define the number of permutations as:
def unique_permutations(counts):
return math.factorial(sum(counts))/product(map(math.factorial, counts))
Now in another language, one would have to worry about the large numbers that can appear in this division as the result of taking large factorials or multiplying numerous smaller factorials. Normally, at some point the calculation will overflow a MAXINT or MAXFLOAT spec. But in python, all integer operations are exact, taking as many digits as required, and integer overflow will not occur by design. Speed might become an issue, but that is a different matter.
How to use it:
>>> unique_permutations([3,3])
20
>>> unique_permutations([2,2])
6
For the math of how to do this, see Wikipedia: Permutation: Permutations of Multisets
If you have N_i
copies of each letter then the number you want is the multinomial coefficient
(N_1 + N_2 + ... + N_k)!/(N_1! N_2! ... N_k!)
For methods for computing this without overflow, see How do I compute multinomials efficiently?.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With