Enumerate multi-subsets for a multiset in Python Given a multiset (i.e., allow repeated elements), enumerate all distinct multi-subsets without using itertools(order is not important).

Example: Let s = 'a,a,b' then print to the console,

a
a,a
b
a,b
a,a,b


I am wondering if my approach (presented below) is efficient, and would appreciate stylistic advice. For example, I am not used to using *args, and in places my approach feels kludgey. 

My attempt:  

Count items in s:

A = s.split(',')
A_counts = defaultdict(int)
for i in A:
    A_counts[i] += 1


In our example we have {'a':2, 'b':1}. Use this to enumerate all tuples of points in the product of sets range(3)xrange(2), i.e., [[0,0],[0,1],[1,0],[1,1],[2,0],[2,1]]. Each tuple corresponds to a unique multi-subset. For example, the tuple [2,1] corresponds to a,a,b and the tuple [2,0] corresponds to a,a.

Enumerate all tuples: 

def enumerate_tuples(*args):
    res = [[i] for i in range(args[0])]
    for arg in args[1:]:
        tmp = [j + [i] for i in range(arg) for j in res]
        res = tmp
    return res


Now print the corresponding multi-subset to console:

ordered_alphabet = list(A_counts)
args = (A_counts[i] + 1 for i in ordered_alphabet)
tuples = enumerate_tuples(*args)

# cycle through tuples printing corresponding string
for tup in tuples:
    if sum(tup) == 0: continue
    group = [ordered_alphabet[i] for i in range(len(tup)) for _ in range(tup[i])]
    out = ','.join(group)
    print(out)
It's a good idea to divide code into functions — this makes it easier to document, test and reuse the code. Here it would make sense to have a function defined like this:

def sub_multisets(elements):
    "Generate the sub-multisets of the iterable elements."
    # code goes here


Then you could call sub_multisets(s.split(',')) or whatever in the main program.
The code in the post omits one of the sub-multisets, namely the empty sub-multiset.
Wherever you have code using defaultdict(int), consider using collections.Counter instead. This is a specialized data structure for counting things. Here you could write:

A_counts = Counter(s.split(','))


with no need for a loop.
To compute the Cartesian product of some collections, use itertools.product. Here we need something like:

product(*[range(n + 1) for n in A_count.values()])


For example:

&gt;&gt;&gt; A_count = Counter('aab')
&gt;&gt;&gt; list(product(*[range(n + 1) for n in A_count.values()])
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]


which are the sub-multiset counts required.
To build the sub-multiset, we can use the Counter.elements method, for example if we have the counts (1, 1) we can write:

&gt;&gt;&gt; tuple(Counter(dict(zip(A_count.keys(), (1, 1)))).elements())
('a', 'b')


Another way to do this would be to use itertools.repeat and itertools.chain:

&gt;&gt;&gt; tuple(chain.from_iterable(repeat(k, n) for k, n in zip(A_count.keys(), (2, 1))))
('a', 'a', 'b')


but I think the Counter.elements approach is slightly simpler.


Putting all this together:

from collections import Counter
from itertools import product

def sub_multisets(elements):
    """Generate the sub-multisets of the iterable elements.
    For example:

    &gt;&gt;&gt; [''.join(s) for s in sub_multisets('aab')]
    ['', 'b', 'a', 'ab', 'aa', 'aab']

    """
    counts = Counter(elements)
    for sub_counts in product(*[range(n + 1) for n in counts.values()]):
        yield Counter(dict(zip(counts.keys(), sub_counts))).elements()