Use combinations_with_replacement for menu bundles
Also published in our Blogger archive.
Use itertools.combinations_with_replacement when a bundle may repeat an item and the order in which a customer names items is irrelevant. This example makes two-item bundles from tea, coffee, and cocoa. It includes ("tea", "tea") as well as mixed bundles such as ("tea", "coffee"), but it does not separately emit ("coffee", "tea"). With three menu items and bundle size two, there are six bundles.
The function operates on input positions and preserves their input ordering in the generated tuples. In a real menu, keep the input sequence in a deliberate display or catalog order. Repeated equal values in the source can still produce repeated-looking bundles because positions are distinct; normalize menu data before generation if item identifiers should be unique. This is a generator, so it can be processed one bundle at a time. Materializing it here is only to make the small result visible and to assert the count.
combinations_with_replacement was added in Python 3.1. The official documentation gives the result count as (n + r - 1)! / r! / (n - 1)! when n > 0; its reference implementation also shows that r == 0 produces one empty tuple. That behavior may need separate handling in an ordering interface.
AI-assistance disclosure: this article was drafted with AI assistance and uses synthetic menu data only.
Source: Python itertools.combinations_with_replacement documentation.
from itertools import combinations_with_replacement
items = ("tea", "coffee", "cocoa")
bundles = list(combinations_with_replacement(items, 2))
assert len(bundles) == 6
assert bundles[0] == ("tea", "tea")
assert bundles[-1] == ("cocoa", "cocoa")
assert ("coffee", "tea") not in bundles
assert ("tea", "coffee") in bundles
for first, second in bundles:
print(f"{first} + {second}")
tea + tea
tea + coffee
tea + cocoa
coffee + coffee
coffee + cocoa
cocoa + cocoa