tags:

views:

123

answers:

5

Let's say I have a list of 10 integers and I want the result of multiplying the first 5 together. Is there a pythonic way of doing this? Python seems to be great with lists :)

+2  A: 

Lot's of ways. Here's one:

>>> a = range(1,10)
>>> reduce(lambda x,y: x*y, a[:5])
120
Triptych
A: 

Using reduce:

reduce(lambda x, y: x*y, mylist[:5])

e.g.,

>>> reduce(lambda x,y:x*y, range(1,5))
24

the reduce() function applies the given function (here, multiplication) over the first two items of the list, hereby reducing them to one item. This is done until there is only one item in the list. This item is returned as the result. This notation is derived from functional languages.

Iterating through the list:

result=1
for i in mylist[:5]:
    result*=i

e.g,

>>> result=1
>>> for i in range(1,5):
    result*=i
>>> result
24

This is the most general way of aggregating some function over all items of a list; It is similar to the way this would have been done Java or C.

Adam Matan
+6  A: 
import operator
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]

print reduce(operator.mul, [v for (k, v,) in enumerate(l) if k < 5])
>> 120

Edit: Better way to do it

print reduce(operator.mul, l[:5])
>> 120
cpharmston
Why not `reduce(operator.mul, l[:5])` ?? People sure love `enumerate()`.
Triptych
Yeah. I edited it for that as you were posting the comment. Still getting used to the "everything is sliceable" thing. Stupid PHP.
cpharmston
`reduce(operator.mul, itertools.islice(l,5))` avoids making a copy of the list which may matter for large enough slices
gnibbler
A: 

See this question.

kgiannakakis
+2  A: 

When there are many ways to do something, I turn to criteria such as readability or speed to decide which code to use. Here is some code which suggests that use_loop and use_reduce are roughly tied in terms of speed (at least for the values tested!)

import operator
import itertools

a=range(1,1000)
def use_loop(a,n):
    result=1
    for num in a[:n]:
        result*=num
    return result

def use_reduce(a,n):
    return reduce(operator.mul, a[:n])

def use_reduce_lambda(a,n):
    return reduce(lambda x,y: x*y, a[:n])

def use_islice_loop(a,n):
    result=1
    for num in itertools.islice(a,n):
        result*=num
    return result

def use_islice_reduce(a,n):
    return reduce(operator.mul, itertools.islice(a,n))

if __name__=='__main__':
    n=50
    print(use_loop(a,n))
    print(use_reduce(a,n))
    print(use_reduce_lambda(a,n))    
    print(use_islice_loop(a,n))
    print(use_islice_reduce(a,n))    

Here are the timing results:

% python -mtimeit -s"import test" "test.use_loop(test.a,50)"
10000 loops, best of 3: 16.1 usec per loop
% python -mtimeit -s"import test" "test.use_reduce(test.a,50)"
100000 loops, best of 3: 16.3 usec per loop
% python -mtimeit -s"import test" "test.use_islice_loop(test.a,50)"
10000 loops, best of 3: 19.6 usec per loop
% python -mtimeit -s"import test" "test.use_islice_reduce(test.a,50)"
10000 loops, best of 3: 19.2 usec per loop
% python -mtimeit -s"import test" "test.use_reduce_lambda(test.a,50)"
10000 loops, best of 3: 32.1 usec per loop

At least for the value of a (1000) and n (50) tested, itertools.islice did not seem to help performance. use_reduce_lambda was significantly slower than it's cousin use_reduce, which used operator.mul. The time required to import operator was not included in the test, however.

Since use_loop and use_reduce seem equally fast, I'd suggest using reduce since its short, idiomatic code should be quite readable to most python programmers. However, in matters of taste I don't think it pays to be too opinionated. Choose what you like best, just be consistent.

PS. As of Python 3+, reduce is no longer a built-in function, but can be accessed through functools.reduce.

unutbu
can you also try one using `itertools.islice(a,n)` instead of `a[:n]`? Seems to take about the same time for n=50, but when n is much larger it would help
gnibbler