I believe this is essentially the same method as the `itertools.combinations`

function, but is there any way to make this code more more perfect in terms of speed, code size and readability :

`def all_subsets(source,size): index = len(source) index_sets = [()] for sz in xrange(size): next_list = [] for s in index_sets: si = s[len(s)-1] if len(s) > 0 else -1 next_list += [s+(i,) for i in xrange(si+1,index)] index_sets = next_list subsets = [] for index_set in index_sets: rev = [source[i] for i in index_set] subsets.append(rev) return subsets `

Yields:

`>>> Apriori.all_subsets(['c','r','i','s'],2) [['c', 'r'], ['c', 'i'], ['c', 's'], ['r', 'i'], ['r', 's'], ['i', 's']] `

There is probably a way to use generators or functional concepts, hopefully someone can suggest improvements.

## Answers

This type of problems lend themselves very well to recursion. A possible implementation, either in list or generator form could be:

```
def all_subsets(di, i) :
ret = []
for j, item in enumerate(di) :
if i == 1 :
ret = [(j,) for j in di]
elif len(di) - j >= i :
for subset in all_subsets(di[j + 1:], i - 1) :
ret.append((item,) + subset)
return ret
def all_subsets_gen(di, i) :
for j, item in enumerate(di) :
if i == 1 :
yield (j,)
elif len(di) - j >= i :
for subset in all_subsets(di[j + 1:], i - 1) :
yield (item,) + subset
>>> all_subsets(range(4), 3)
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
>>> list(all_subsets_gen(range(4), 3))
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
```

If you are going to run this on large sets, you may want to memoize intermediate results to speed things up.