Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - List comprehension with 2 for loops & a ADD AND operand

outgoing=[
        [27, 42, 66, 85, 65, 64, 68, 68, 77, 58],
        [24, 39, 58, 79, 60, 62, 67, 62, 55, 35],
        [3, 3, 8, 6, 5, 2, 1, 6, 22, 23],
        [3, 3, 8, 6, 5, 2, 1, 6, 22, 23],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       ]
incoming=[
        [459, 469, 549, 740, 695, 629, 780, 571, 574, 599],
        [420, 443, 504, 714, 669, 604, 745, 537, 537, 562],
        [39, 26, 45, 26, 26, 25, 35, 34, 37, 37],
        [26, 25, 27, 26, 26, 25, 35, 34, 37, 37],
        [13, 1, 18, 0, 0, 0, 0, 0, 0, 0],
       ]

I want to create a list which is the combination of incoming + outgoing. E.g incoming[0][0] should be added to outgoing[0][0], incoming[0][1] should be added to outgoing[0][1] and so on. A list called joint will be produced and have the exact same structure as incoming and outgoing (e.g a list of 5 lists of 10 elements). The code which does this is below:

joint=incoming
for x in range(5):
    for y in range(10):
        joint[x][y]+=outgoing[x][y]

This works fine. But I would like it as a list comprehension.

[[joint[x][y]+=outgoing[x][y]] for x in range(5) for y in range(10))]

The above doesn't work, can someone explain why this failed and give an example of a correct list comprehension.

like image 506
Phoenix Avatar asked Dec 17 '13 15:12

Phoenix


3 Answers

You want to use zip() here to combine your lists into pairs:

joint = [[x + y for x, y in zip(*row)] for row in zip(outgoing, incoming)]

The outer loop pairs up the rows from outgoing and incoming into pairs, so outgoing[0] together with incoming[0], outgoing[1] with incoming[1]`, etc.

The inner loop then pairs up the paired rows, putting outgoing[0][0] and incoming[0][0] together into a tuple, followed by outgoing[0][1] and incoming[0][1], and so on. The inner loop produces one row of summed values.

Demo:

>>> [[x + y for x, y in zip(*row)] for row in zip(outgoing, incoming)]
[[486, 511, 615, 825, 760, 693, 848, 639, 651, 657], [444, 482, 562, 793, 729, 666, 812, 599, 592, 597], [42, 29, 53, 32, 31, 27, 36, 40, 59, 60], [29, 28, 35, 32, 31, 27, 36, 40, 59, 60], [13, 1, 18, 0, 0, 0, 0, 0, 0, 0]]
>>> from pprint import pprint
>>> pprint(_)
[[486, 511, 615, 825, 760, 693, 848, 639, 651, 657],
 [444, 482, 562, 793, 729, 666, 812, 599, 592, 597],
 [42, 29, 53, 32, 31, 27, 36, 40, 59, 60],
 [29, 28, 35, 32, 31, 27, 36, 40, 59, 60],
 [13, 1, 18, 0, 0, 0, 0, 0, 0, 0]]

Your specific code doesn't work because you cannot use assignment statements (enhanced or otherwise) inside an expression. The += part of your code cannot be used like that.

Another problem is that joint was just another reference to incoming, not a copy. You altered the same list via a different reference to it.

like image 133
Martijn Pieters Avatar answered Nov 07 '22 17:11

Martijn Pieters


You need something like

joint = [[sum(x) for x in zip(a, b)] for a, b in zip(incoming, outgoing)]

Your attempted list comprehension doesn't work because it tries to assign to joint[x][y] before the structure of joint (i.e. list of lists) is set up. Your earlier code works because joint is incoming (note: not a copy, it is a reference to the same object), so the structure is there.

like image 22
jonrsharpe Avatar answered Nov 07 '22 17:11

jonrsharpe


Firstly flatten both lists using a nested loop-comprehension and then use the built-in zip() function in-conjunction with the map() and sum() functions

So Try this:

flattend1 = [k for i in outgoing for k in i]
flattend2 = [k for i in incoming for k in i]

print map(sum,zip(flattend1,flattend2))
like image 31
K DawG Avatar answered Nov 07 '22 17:11

K DawG