11

I am able to use map and sum to achieve this functionality, but how to use reduce?

There are 2 lists: a, b, they have same number of values. I want to calculate

a[0]*b[0]+a[1]*b[1]+...+a[n]*b[n]

The working version I wrote using map is

value =  sum(map(lambda (x,y): x*y, zip(a, b)))

How to use reduce then? I wrote:

value =  reduce(lambda (x,y): x[0]*y[0] + x[1]*y[1], zip(a, b)))

I got the error "TypeError: 'float' object is unsubscriptable".

Can anyone shed some light on this?

Moberg
  • 5,253
  • 4
  • 38
  • 54
zs2020
  • 53,766
  • 29
  • 154
  • 219
  • 1
    Your lambda takes two two-element tuples. That works fine when reducing the first two elements of your list, but now the next reduction will work on the result of your lambda (which is a float) and the next element of the list (which is a tuple), and your lambda can't handle that. Your lambda needs to take a number and a tuple, and seed the number with an initial value (as antonakos' answer does). – dfan Apr 07 '11 at 14:10

6 Answers6

8

The first argument of the lambda function is the sum so far and the second argument is the next pair of elements:

value = reduce(lambda sum, (x, y): sum + x*y, zip(a, b), 0)
antonakos
  • 8,261
  • 2
  • 31
  • 34
8

A solution using reduce and map,

from operator import add,mul

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

print reduce(add,map(mul,a,b))
lafras
  • 8,712
  • 4
  • 29
  • 28
7

I would do it this way (I don't think you need lambda)...

sum(x*y for x, y in zip(a, b))

This also seems slightly more explicit. Zip AB, multiply them, and sum up the terms.

Andrew White
  • 52,720
  • 19
  • 113
  • 137
2

an update on the accepted answer (by @antonakos):

The ability to unpack tuple parameters was removed in Python 3.x

so the solution

value = reduce(lambda sum, (x, y): sum + x*y, zip(a, b), 0)

might give you a syntax error:

 value = reduce(lambda sum, (x,y): sum + x*y, zip(a,b), 0)
                            ^
 SyntaxError: invalid syntax

To work on both Python 2.x and 3.x, You can manually unpack the tuple instead:

from functools import reduce
a = [1,2,3]
b = [1,4,8]
value = reduce(lambda sum, xy: sum + xy[0]+xy[1], zip(a,b), 0)
print("result:", value)

result: 19

Alg_D
  • 2,242
  • 6
  • 31
  • 63
1

Difficulties with reduce happen when you have incorrect map.

Let's take expression: value = sum(map(lambda (x,y): x*y, zip(a, b)))

Map is transformation. We need it to convert tuples into simple flat values. In your case it will look like:

map(lambda x: x[0]*x[1], zip(a,b))

And then, if you want to express sum via reduce - it will look like:

reduce(lambda x,y: x + y, map)

So, here is example:

a = [1,2,3]
b = [4,5,6] 
l = zip(a,b)
m = map(lambda x: x[0]*x[1], l)
r = reduce(lambda x,y: x + y, m)
Nikolay Fominyh
  • 8,946
  • 8
  • 66
  • 102
1

it looks like you want an inner product. use an inner product. https://docs.scipy.org/doc/numpy/reference/generated/numpy.inner.html

np.inner(a, b) = sum(a[:]*b[:])

Ordinary inner product for vectors:

a = np.array([1,2,3])
b = np.array([0,1,0])
np.inner(a, b)

output: 2

A multidimensional example:

a = np.arange(24).reshape((2,3,4))
b = np.arange(4)
np.inner(a, b)

output: array([[ 14, 38, 62],[ 86, 110, 134]])

chrisg
  • 200
  • 8
  • It is good that you mention "inner product", because that gives us some mathematical and conceptual background. – Ideogram Dec 06 '18 at 07:55