new itertools functions in Python 2.6

Mensanator mensanator at aol.com
Wed Jul 16 02:20:58 EDT 2008


On Jul 15, 1:44 am, Raymond Hettinger <pyt... at rcn.com> wrote:
> On Jul 14, 1:26 pm, Mensanator <mensana... at aol.com> wrote:
>
> > ##  Combinations with replacement
> > ##  -----------------------------
> > ##  aaa aab aac aad aae abb abc abd abe acc acd ace
> > ##  add ade aee bbb bbc bbd bbe bcc bcd bce bdd bde
> > ##  bee ccc ccd cce cdd cde cee ddd dde dee eee
> > ##
> > ##  actual words: 35    (m+n-1)!/(n!(m-1)!) words: 35
>
> > Although it works, it's somewhat slow as we have to iterate
> > over the entire Cartesian Product and the filter list(x)==sorted(x)
> > has got to be expensive (it's slower than the nested loop algorithm).
>
> > Is there a better way to get Combinations With Replacement
> > using itertools?
>
> There may a technique to start with the combinations without
> replacement and then grow the result by repeating elements:

Great idea, I had only considered making a sub=set. It never
occured to me to try and make a super=set.

Thanks for the suggestions, they've given me some
ideas to try.

>
>    result = set(combinations('abcde', 3))
>    # transform 'ab ac ad ae bc bd be cd ce de' into 'aab abb aac
> acc ...'
>    for c in combinations('abcde', 2):
>        # transform 'ab' --> 'aab abb'
>        for i in range(2):
>            result.add(c[:i] + c[i]*1 + c[i:])
>    for c in combinations('abcde', 1):
>        for i in range(1):
>            # 'a' --> 'aaa'
>            result.add(c[:i] + c[i]*2 + c[i:])
>
> If you generalize the above, it may solve the problem using itertools
> as a starting point.
>
> Alternatively, it's not too hard to transform the pure python version
> given in the docs to one that supports combinations with replacement:

I was trying to avoid that kind of solution.

ifilter(product()) is exactly the kind of thing
I'm looking for, just wondering if there's a
better way, using a different combination of
functions.

>
> def combinations_with_replacement(iterable, r):
>     pool = tuple(iterable)
>     n = len(pool)
>     indices = [0] * r
>     yield tuple(pool[i] for i in indices)
>     while 1:
>         for i in reversed(range(r)):
>             if indices[i] != n - 1:
>                 break
>         else:
>             return
>         indices[i] += 1
>         for j in range(i+1, r):
>             indices[j] = indices[j-1]
>         yield tuple(pool[i] for i in indices)
>
> Raymond




More information about the Python-list mailing list