Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #60409 > unrolled thread

Re: Recursive generator for combinations of a multiset?

Started byOscar Benjamin <oscar.j.benjamin@gmail.com>
First post2013-11-25 12:15 +0000
Last post2013-11-25 12:15 +0000
Articles 1 — 1 participant

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Recursive generator for combinations of a multiset? Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-11-25 12:15 +0000

#60409 — Re: Recursive generator for combinations of a multiset?

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-11-25 12:15 +0000
SubjectRe: Recursive generator for combinations of a multiset?
Message-ID<mailman.3164.1385381745.18130.python-list@python.org>
On 21 November 2013 13:01, John O'Hagan <research@johnohagan.com> wrote:
> In my use-case the first argument to multicombs is a tuple of words
> which may contain duplicates, and it produces all unique combinations
> of a certain length of those words, eg:
>
> list(multicombs(('cat', 'hat', 'in', 'the', 'the'), 3))
>
> [('cat', 'hat', 'in'), ('cat', 'hat', 'the'), ('cat', 'in', 'the'),
> ('cat', 'the', 'the'), ('hat', 'in', 'the'), ('hat', 'the', 'the'),
> ('in', 'the', 'the')]

I still don't understand what you're actually doing well enough to
know whether there is a better general approach to the problem. For
the specific thing you requested, here is a recursive multiset
combinations generator. Does it do what you wanted?

#!/usr/bin/env python

def multicombs(it, r):
    words = []
    last = None
    for N, word in enumerate(it):
        if word == last:
            words[-1][1] += 1
        else:
            words.append([word, 1])
            last = word
    cumulative = 0
    for n in range(len(words)-1, -1, -1):
        words[n].append(cumulative)
        cumulative += words[n][1]
    return _multicombs((), words, r)

def _multicombs(prepend, words, r):
    if r == 0:
        yield prepend
        return
    (word, count, rem), *remaining = words
    for k in range(max(r-rem, 0), min(count, r) + 1):
        yield from _multicombs(prepend + (word,) * k, remaining, r-k)

expected = [
       ('cat', 'hat', 'in'),
       ('cat', 'hat', 'the'),
       ('cat', 'in', 'the'),
       ('cat', 'the', 'the'),
       ('hat', 'in', 'the'),
       ('hat', 'the', 'the'),
       ('in', 'the', 'the'),
    ]

output = list(multicombs(('cat', 'hat', 'in', 'the', 'the'), 3))

assert len(expected) == len(output)
assert set(expected) == set(output)  # The order is different


Oscar

[toc] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web