2

I was looking at creating a simple generator to sum the values of two list with nested values. Using from stack this answer https://stackoverflow.com/a/17014386/461887 and this answer What does the "yield" keyword do in Python?

So I created 2 lists

a = ([1, 2], [2, 3])

b = ([3, 4], [5, 6])

created a generator which errored.

In [10]: def sumNest(item1, item2):
    ...:     try:
    ...:         for i in iter(item1):
    ...:             for j in iter(item2):
    ...:                 yield i + j
    ...:     except TypeError:
    ...:         yield item
    ...:         

I can create it without error but it doesn't work(in the way I expect).

In [14]: def sumNest(item1, item2):
    ...:     try:
    ...:         for i in iter(item1):
    ...:             for j in iter(item2):
    ...:                 k = (i + j)
    ...:                 yield k
    ...:     except TypeError:
    ...:         yield item
    ...:         

Result of my use expecting the summed output.

In [17]: sumNest(a, b)
Out[17]: <generator object sumNest at 0x7f313e6e74b0>

In [18]: answer = sumNest(a, b)

In [19]: answer
Out[19]: <generator object sumNest at 0x7f313e6e7230>

In [20]: print answer
<generator object sumNest at 0x7f313e6e7230>

In [21]: answer(a, b)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-badcb4bdaf5d> in <module>()
----> 1 answer(a, b)

TypeError: 'generator' object is not callable

Which led me to go back a bit and get this result where instead of addition of lists as expected I ended up with concatentation.

a = ([1, 2], [2, 3])

b = ([3, 4], [5, 6])

for i in a:
    ...:     for j in b:
    ...:         print(i + j)
    ...:         
[1, 2, 3, 4]
[1, 2, 5, 6]
[2, 3, 3, 4]
[2, 3, 5, 6]

Now thats a nice result, but not again expected(addition expected) so a result like:

([4, 6], [7, 9])

What is it that I am not getting about iteration, lists and yeild that I need to?

Community
  • 1
  • 1
sayth
  • 6,696
  • 12
  • 58
  • 100

3 Answers3

2

A generator object needs to be looped over:

for summed in sumNest(a, b):
    print summed

Alternatively, you can use the next() function on a generator to get one value from it.

Your first example had a syntax error, because you misspelled yield. Your exception handler tries to yield item, but the function doesnt actually define that name.

Note that neither of your solutions flattens the lists, you are still 'summing' tuples.

Working example:

>>> a = ([1, 2], [2, 3])
>>> b = ([3, 4], [5, 6])
>>> def summedProduct(iter1, iter2):
...     for i in iter(iter1):
...         for j in iter(iter2):
...             yield i + j
... 
>>> for summed in summedProduct(a, b):
...     print summed
... 
[1, 2, 3, 4]
[1, 2, 5, 6]
[2, 3, 3, 4]
[2, 3, 5, 6]

If instead you wanted to flatten the lists, flatten them first, then zip() the flattened results together to sum:

def summedNested(nested1, nested2):
    flattened1 = (v for nested in nested1 for v in nested)
    flattened2 = (v for nested in nested2 for v in nested)
    for i, j in zip(flattened1, flattened2):
        yield i + j

Demo:

>>> def summedNested(nested1, nested2):
...     flattened1 = (v for nested in nested1 for v in nested)
...     flattened2 = (v for nested in nested2 for v in nested)
...     for i, j in zip(flattened1, flattened2):
...         yield i + j
... 
>>> for summed in summedNested(a, b):
...     print summed
... 
4
6
7
9
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • @Martjin Pieters So I searched for flatten lists, but it still just joins them. not add a[0][0] + b[0][0] and so on. reduce(lambda x,y: x+y,(a, b)) Out[27]: ([1, 2], [2, 3], [3, 4], [5, 6]) from answer here http://stackoverflow.com/a/952952/461887 – sayth Nov 19 '13 at 12:23
  • actually, what would the expected outcome be for summing `a` and `b`? – Martijn Pieters Nov 19 '13 at 12:27
  • So for `[1, 2] + [3, 4]`, what would the expected sum be? `[4, 6]`? Or `10`? – Martijn Pieters Nov 19 '13 at 12:28
  • 1
    Or did you expect to `map(sum, zip([1, 2, 2, 3], [3, 4, 5, 6]))`, so `[4, 6, 7, 9]`? – Martijn Pieters Nov 19 '13 at 12:34
  • @Martjin Pieters. Correct I expected to receive the result the combination of map sum & zip provided – sayth Nov 19 '13 at 12:37
  • @Martjin Pieters. Does that mean though if I had 10 lists to flatten I would need to create flatten1, flaaten2, flatten3 etc? – sayth Nov 20 '13 at 22:08
  • No, you can flatten lists in a loop too, and delegate flattening to a function if needed. – Martijn Pieters Nov 20 '13 at 22:21
2

answer is generator object, you can make (generate) list from it:

result = list(answer)
ndpu
  • 22,225
  • 6
  • 54
  • 69
1

Simply calling a generator will give you a generator object. You need to iterate it or use next function with it, to get the values. For example,

next(sumNest(a, b))

would have worked for you. Or iterating with a loop

for item in sumNext(a, b):
    print item

For example

def sumNest(item1, item2):
  try:
      for i in iter(item1):
          for j in iter(item2):
              k = (i + j)
              yield k
  except TypeError:
      yield item1

print next(sumNest([1, 2], [3, 4]))
print
for item in sumNest([1, 2], [3, 4]):
    print item,

Output

4

4 5 5 6

And when you say, I created 2 lists

a = ([1, 2], [2, 3])
b = ([3, 4], [5, 6])

you created tuples not lists.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • shouldn't the output 4 5 5 6 have been 4 6 7 9 being the addition of the two lists at their matching indexes. – sayth Nov 19 '13 at 12:28