using Python reduce over a list of pairs
Asked Answered
R

1

6

I'm trying to pair together a bunch of elements in a list to create a final object, in a way that's analogous to making a sum of objects. I'm trying to use a simple variation on reduce where you consider a list of pairs rather than a flat list to do this. I want to do something along the lines of:

nums = [1, 2, 3]
reduce(lambda x, y: x + y, nums)

except I'd like to add additional information to the sum that is specific to each element in the list of numbers nums. For example for each pair (a,b) in the list, run the sum as (a+b):

nums = [(1, 0), (2, 5), (3, 10)]
reduce(lambda x, y: (x[0]+x[1]) + (y[0]+y[1]), nums)

This does not work:

>>> reduce(lambda x, y: (x[0]+x[1]) + (y[0]+y[1]), nums)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
TypeError: 'int' object is unsubscriptable

Why does it not work? I know I can encode nums as a flat list - that is not the point - I just want to be able to create a reduce operation that can iterate over a list of pairs, or over two lists of the same length simultaneously and pool information from both lists. thanks.

Rattly answered 21/10, 2012 at 16:42 Comment(2)
Do you want the result of the reduce to be a tuple?Cleanser
Do you have to use reduce? I prefer the simple sum(x[0] + x[1] for x in nums)Medium
P
6

Looking at the lambda you passed to reduce:

f = lambda x, y: (x[0]+x[1]) + (y[0]+y[1])

The value returned by f will be passed as a parameter to another invocation of f. But while f expects its parameters to be pairs, the value it returns is an int. You need to make this function return a pair as well. For example, this would sum up the left and right sides separately:

>>> nums = [(1, 0), (2, 5), (3, 10)]
>>> reduce(lambda x, y: (x[0] + y[0], x[1] + y[1]), nums)
(6, 15)

Another thing you can do is treat the accumulated value differently from the list elements: You can make the accumulated value an int, while the list elements are pairs. If you do this, you must pass the initializer argument to reduce, so that the accumulator is initialized correctly to an int:

>>> nums = [(1, 0), (2, 5), (3, 10)]
>>> reduce(lambda acc, y: acc + y[0] + y[1], nums, 0)
21
Philip answered 21/10, 2012 at 16:47 Comment(2)
Is there a way to just get an iterator from reduce over the pairs? Something analogous to enumerate(mylist) for lists, where it returns not only the current element but also its position in the list. Can the lambda in reduce get access to the number of the pair being used in the above example?Rattly
@Rattly You can use enumerate(mylist) as the input to reduce.Philip

© 2022 - 2024 — McMap. All rights reserved.