7

I am trying to sum the product of two different list items in the same line using for loop, but I am not getting the output as expected.

My example code:

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

sum = 0              # optional element

score = ((sum+(a(i)*b(i)) for i in range(len(a)))

print score

output:

<generator object <genexpr> at 0x027284B8>

expected output:

32                   # 0+(1*4)+(2*5)+(3*6)
mertyildiran
  • 6,477
  • 5
  • 32
  • 55
Ravy
  • 89
  • 1
  • 1
  • 8
  • 1
    You shouldn't use `sum` as a variable name because that shadows the built-in `sum` function. As you can see in the answers below, that's a very useful function! But if you shadow its name with an integer by doing `sum = 0` then you will get the `TypeError: 'int' object is not callable` error message when you try to call it. – PM 2Ring Jan 24 '17 at 06:41

9 Answers9

15

Just zip the lists to generate pairs, multiply them and feed to sum:

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> sum(x * y for x, y in zip(a, b))
32

In above zip will return iterable of tuples containing one number from both lists:

>>> list(zip(a, b))
[(1, 4), (2, 5), (3, 6)]

Then generator expression is used to multiply the numbers together:

>>> list(x*y for x, y in list(zip(a, b)))
[4, 10, 18]

Finally sum is used to sum them together for final result:

>>> sum(x*y for x, y in list(zip(a, b)))
32
niemmi
  • 17,113
  • 7
  • 35
  • 42
  • I am getting this error: `Traceback (most recent call last): File "", line 1, in TypeError: 'int' object is not callable` – Ravy Jan 24 '17 at 06:19
  • @JitendraReddy Feel free to post a new question. Be sure to include the code which causes the error. – Code-Apprentice Jan 24 '17 at 06:20
  • @JitendraReddy Did you run exactly the same example as in the answer? It should work the same for both Python 3.x and 2.7. – niemmi Jan 24 '17 at 06:21
  • 1
    @JitendraReddy you are getting that error because you previously reassigned the name `sum` (a builtin function) to refer to `0` (an integer). Restart your python console and try not to override builtins, or alternatively just run `sum = __builtins__.sum` to get the `sum()` function back. – Will Hardy Jan 24 '17 at 14:59
4

You have some problems in your code, first off you cant index your list with parenthesis you need [], secondly you've created a generator not a number.

You need to zip your lists first:

In [3]: sum(i*j for i,j in zip(a, b))
Out[3]: 32

Or as a functional approach use operator.mul within map and sum:

In [11]: from operator import mul 

In [12]: sum(map(mul, a, b))
Out[12]: 32
Mazdak
  • 105,000
  • 18
  • 159
  • 188
3

A generator by itself, even if applied so as to generate the list result, will just give you a list of the products. You still need to do something to add up the elements of the list, which you can't do inside your generator.

Your method looks like you've mixed generator syntax with a traditional for loop, which would look like this:

score = 0
for i in range(len(a)):
  score = score + a[i]*b[i]

The cleanest, or at least most Pythonic, solution probably uses zip to combine the lists, a list comprehension to multiply the elements, and sum to add them all up:

score = sum([x*y for (x,y) in zip(a,b)])

You could also use reduce for the full-on functional approach (note that you have to import it from functools if you use Python 3):

score = reduce(lambda s,t: s+t[0]*t[1], zip(a,b), 0)
Mark Reed
  • 91,912
  • 16
  • 138
  • 175
  • Yeah I noticed too :-) But I figured it would be helpful to note the difference just in case unsuspecting Python 3 users try to use your answer. – Christian Dean Jan 24 '17 at 06:26
2

Let's take a close look at your code:

score = ((sum+(a(i)*b(i)) for i in range(len(a)))

The right hand side of this statement is a generator expression. Think of a generator as a lazy list. It doesn't actually sum anything, so to be more correct you should do

score = (a[i]*b[i] for i in range(len(a)))

(Note the brackets, not parentheses, for subscripting the lists.)

Now score is a generator which "contains" the products of corresponding elements of the original lists a and b.

The next step is to iterate over the list to sum the elements:

for x in score:
    sum += x
print(sum)

As others have already posted, you can do this all in one line with zip() and sum() built-in functions:

sum([x*y for x, y in zip(a, b)])
Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
1
a = [1,2,3]
b = [4,5,6]
ls = [x * y for x, y in zip(a, b)]
x = sum(ls) 
print x
Shivkumar kondi
  • 6,458
  • 9
  • 31
  • 58
0

You can try:

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> sum(map(lambda x: x[0] * x[1], zip(a, b)))
32
Harsha Biyani
  • 7,049
  • 9
  • 37
  • 61
0

If you have a large list, you might consider taking the dot product using numpy arrays

import numpy as np
arr1 = np.random.randint(0,2,300)
arr2 = np.random.randint(0,2500,300)

list1 = list(arr1)
list2 = list(arr2)

%timeit sum([x * y for x, y in zip(list1,list2)])

38.9 µs ± 795 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit arr1 @ arr2

1.23 µs ± 89.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
0

an unconventional method: the LAMBDA function.

a = [1,2,3]
b = [4,5,6]
pwr = sum(map(lambda a,b:a*b, a,b))
print(pwr)
Emir
  • 1
-1

Since Python 3.12, there is a new built-in function in the math module - sumprod:

from math import sumprod

a = [1,2,3]
b = [4,5,6]
print(sumprod(a, b))
# 32
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61