@@ -594,35 +594,51 @@ def partition(pred, iterable):
594594 t1 , t2 = tee (iterable )
595595 return filterfalse (pred , t1 ), filter (pred , t2 )
596596
597- def partition_int (n , lower = 1 ):
597+ def partition_int (n , lower = 1 , upper = None ):
598598 """Yield all ordered sequences of smaller positive integers that sum to `n`.
599599
600600 `n` must be an integer >= 1.
601601
602- `lower` is an optional lower limit for the members of the sum. Each number
603- must be `>= lower`. (Most of the splits are a ravioli consisting mostly of
604- ones, so it is much faster to not generate those than to filter them out
605- from the result. The default value `lower=1` generates everything.)
602+ `lower` is an optional lower limit for each member of the sum. Each member
603+ of the sum must be `>= lower`.
604+
605+ (Most of the splits are a ravioli consisting mostly of ones, so it is much
606+ faster to not generate such splits than to filter them out from the result.
607+ The default value `lower=1` generates everything.)
608+
609+ `upper` is, similarly, an optional upper limit; each member of the sum
610+ must be `<= upper`. The default `None` means no upper limit (effectively,
611+ in that case `upper=n`).
612+
613+ It must hold that `1 <= lower <= upper <= n`.
606614
607615 Not to be confused with `unpythonic.it.partition`, which partitions an
608616 iterable based on a predicate.
609617
610618 **CAUTION**: The number of possible partitions grows very quickly with `n`,
611- so in practice this is only useful for small numbers. A possible use case
612- is determining the number of letters to allocate for the components of an
613- anagram.
619+ so in practice this is only useful for small numbers, or with a lower limit
620+ that is not too much smaller than `n` itself. A possible use case is
621+ determining the number of letters to allocate for each component of an
622+ anagram that may consist of several words.
614623
615624 See:
616625 https://en.wikipedia.org/wiki/Partition_(number_theory)
617626 """
618- # sanity check and fail-fast
627+ # sanity check the preconditions, fail-fast
619628 if not isinstance (n , int ):
620629 raise TypeError ('n must be integer; got {:s}' .format (str (type (n ))))
630+ if not isinstance (lower , int ):
631+ raise TypeError ('lower must be integer; got {:s}' .format (str (type (lower ))))
632+ if upper is not None and not isinstance (upper , int ):
633+ raise TypeError ('upper must be integer; got {:s}' .format (str (type (upper ))))
634+ upper = upper if upper is not None else n
621635 if n < 1 :
622636 raise ValueError ('n must be positive; got {:d}' .format (n ))
637+ if lower < 1 or upper < 1 or lower > n or upper > n or lower > upper :
638+ raise ValueError ('it must hold that 1 <= lower <= upper <= n; got lower={:d}, upper={:d}' .format (lower , upper ))
623639
624640 def _partition (n ):
625- for k in range (n , lower - 1 , - 1 ):
641+ for k in range (min ( n , upper ) , lower - 1 , - 1 ):
626642 m = n - k
627643 if m == 0 :
628644 yield (k ,)
0 commit comments