This is a combination of (a) finding lists [k_1, ..., k_n]
such that each k_i
equals either k_(i-1)
or k_(i-1)+1
, and (b) finding the unique permutations of those lists.
The first can be done using a recursive function:
def combinations(n, k=0):
if n > 1:
yield from ([k] + res for i in (0, 1)
for res in combinations(n-1, k+i))
else:
yield [k]
For lists with n
elements, there will be 2^(n-1)
such combinations:
>>> list(combinations(2))
[[0, 0], [0, 1]]
>>> list(combinations(3))
[[0, 0, 0], [0, 0, 1], [0, 1, 1], [0, 1, 2]]
>>> list(combinations(4))
[[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 2], [0, 1, 1, 1], [0, 1, 1, 2], [0, 1, 2, 2], [0, 1, 2, 3]]
Combine that with itertools.permutations
and filter out duplicates to get the final result:
import itertools
def all_combinations(n):
return (x for combs in combinations(n)
for x in set(itertools.permutations(combs)))
Example:
>>> list(all_combinations(3))
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
>>> sum(1 for _ in all_combinations(4))
75
>>> sum(1 for _ in all_combinations(5))
541
Note: Generating all n!
permutations and then filtering the duplicates can be very wasteful even for slightly larger values of n
. There are smarter ways of generating only unique permutations that can be used instead of itertools.permutations
, see e.g. here or here.