Pierric Mazodier
Pierric Mazodier

Reputation: 55

Python: recursive generator

I want to recursively generate all the possible sums of the slices of a string of digits. For example:

Input: '891'
Output: 18, 99, 90, 891

In details:
    8+9+1 = 18
    8+91 = 99
    89+1 = 90
    891 = 891

However, the code I wrote yields generators of generators:

# s: string of digits, c: sum of slices
def rec(s,c):
    for i in range(1,len(s)+1):
        if s=='': yield c
        else: yield rec(s[i:],c+int(s[:i]))

How can I fix it?

Upvotes: 5

Views: 493

Answers (3)

Ajax1234
Ajax1234

Reputation: 71451

You can generate the combinations and then use functools.reduce:

def slices(d, c = []):
  if not d:
     yield list(map(int, c))
  else:
     if c:
        yield from slices(d[1:], c[:-1]+[c[-1]+d[0]])
     yield from slices(d[1:], c+[d[0]])

import operator as op, functools
print([functools.reduce(op.add, i) for i in slices('891')][::-1])
#note: printing reverse of list to produce proper order of desired output

Output:

[18, 99, 90, 891]

Upvotes: 3

jwodder
jwodder

Reputation: 57470

To yield the elements of a generator instead of the generator itself, use yield from:

# s: string of digits, c: sum of slices
def rec(s,c):
    for i in range(1,len(s)+1):
        if s=='': yield c
        else: yield from rec(s[i:],c+int(s[:i]))
        #     ^^^^^^^^^^

Upvotes: 1

orlp
orlp

Reputation: 117671

It can sometimes be tricky to get right. But you are confusing yourself by adding the extra argument:

def rec(s):
    # No split.
    yield int(s)

    # Split.
    for i in range(1, len(s)):
        left = int(s[:i])
        for right in rec(s[i:]):
           yield left + right

And indeed:

>>> list(rec("891"))
[891, 99, 18, 90]

Upvotes: 6

Related Questions