@@ -838,10 +838,10 @@ and :term:`generators <generator>` which incur interpreter overhead.
838
838
839
839
.. testcode ::
840
840
841
- from collections import deque
841
+ from collections import Counter, deque
842
842
from contextlib import suppress
843
843
from functools import reduce
844
- from math import sumprod, isqrt
844
+ from math import comb, prod, sumprod, isqrt
845
845
from operator import itemgetter, getitem, mul, neg
846
846
847
847
def take(n, iterable):
@@ -1127,6 +1127,12 @@ The following recipes have a more mathematical flavor:
1127
1127
n -= n // prime
1128
1128
return n
1129
1129
1130
+ def multinomial(*counts):
1131
+ "Number of distinct arrangements of a multiset."
1132
+ # Counter('abracadabra').values() -> 5 2 1 1 2
1133
+ # multinomial(5, 2, 1, 1, 2) → 83160
1134
+ return prod(map(comb, accumulate(counts), counts))
1135
+
1130
1136
1131
1137
.. doctest ::
1132
1138
:hide:
@@ -1730,6 +1736,12 @@ The following recipes have a more mathematical flavor:
1730
1736
>>> ' ' .join(it)
1731
1737
'DEF1'
1732
1738
1739
+ >>> multinomial(5 , 2 , 1 , 1 , 2 )
1740
+ 83160
1741
+ >>> word = ' coffee'
1742
+ >>> multinomial(* Counter(word).values()) == len (set (permutations(word)))
1743
+ True
1744
+
1733
1745
1734
1746
.. testcode ::
1735
1747
:hide:
0 commit comments