The suggestions about using a fast set structure are good, but you get best results if you don't generate the items you don't need in the first place. Let's do a slightly different representation of x
:
from collections import OrderedDict
x = OrderedDict([("$5", 2), ("$10", 2), ("TAX", 2), ("20%", 1), ("BOGO", 3)])
Then, the following function should get you non-repeating permutations:
from copy import copy
def permutations_unique(x, curr_list=[]):
if not x:
yield curr_list
return
last_item = None
if curr_list:
last_item = curr_list[-1]
for item in x:
if item != last_item:
for j in range(1, x[item] + 1):
xchild = copy(x)
xchild[item] -= j
if xchild[item] == 0:
del xchild[item]
for y in permutations_unique(xchild, curr_list + [item] * j):
yield y
It's a recursion. At each step we choose the item and the number of repetitions. Plus we avoid choosing the same item at the next level of the recursion.
For your problem instance, this code is slower than the approach with a set
. However, try with x = [1] * 30
for a counterexample.