Jill
Jill

Reputation: 11

Reduce function in Python

I used the reduce function to multiply all the elements of a list as follows.

l = [1,2,3,4,5]
reduce(lambda x,y:x*y,l) #returns 120

Now, suppose I have a list, l = [1,'apple',2,'apple','apple'], and I want to count how many times the word "apple" appears in the list. Is this possible using reduce?

I'm aware I can use l.count('apple'), but I want to know if a reduce solution is possible.

Upvotes: 0

Views: 4646

Answers (7)

Yogananda Sai
Yogananda Sai

Reputation: 1

Custom reduce function in python

def my_reduce(func,sequence) :
    res=sequence[0]
    for variable in sequence[1:]:
        res =func(variable,res)

    return res


def my_sum(a,b):
    return a+b


seq=[1,2,3,4,5]
print(str(my_reduce(my_sum,seq)))

Upvotes: 0

andrew cooke
andrew cooke

Reputation: 46892

This is easiest using an initializer (the extra 0 at the end of the call to reduce), so you only need to convert the second argument:

reduce(lambda x, y: x + (1 if y=='apple' else 0), [1,'apple',2,'apple','apple'], 0)

Or you can reduce something that has been transformed by a map into 0 and 1:

reduce(lambda x, y: x+y, map(lambda x: 1 if x=='apple' else 0,  [1,'apple',2,'apple','apple']))

But there are lots of ways to make this more natural:

  • use list comprehensions rather than reduce
  • use the operators package instead of defining your own function for addition
  • user itertools

(And the counter suggestion above is really cool - I don't think I even knew that existed.)

A simpler (but not very efficient) approach would be:

len([x for x in [1,'apple',2,'apple','apple'] if x=='apple'])

Upvotes: 2

eyquem
eyquem

Reputation: 27585

from operator import mul
from time import clock

n= 10000

li = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

te = clock()
for i in xrange(n):
    x = reduce(mul,li)
print clock()-te


te = clock()
for i in xrange(n):
    y = reduce(lambda a,b: a*b,li)
print clock()-te


print x==y

result

0.0616016840129
0.124420003101
True

.

li = [1,78,2,2,12,45,1,2,8,1,2,5,4,2]


te = clock()
for i in xrange(n):
    x = li.count(2)
print clock()-te

te = clock()
for i in xrange(n):
    y = sum(1 for a in li if a==2)
print clock()-te

te = clock()
for i in xrange(n):
    z = len([a for a in li if a==2])
print clock()-te

print x==y==z

produces

0.0110332458455
0.0428308625817
0.0518741907142
True

Upvotes: 0

sth
sth

Reputation: 229914

If you use a "real" function instead of a lambda function solutions to problems like this usually become much clearer:

def count_apples(acc, v):
   if v == 'apple':
      return acc+1
   else:
      return acc

l = [1,'apple',2,'apple','apple']
print reduce(count_apples, l, 0)

Upvotes: 1

utdemir
utdemir

Reputation: 27266

>>> l = [1,'apple',2,'apple','apple']
>>> reduce(lambda s, i: s+1 if i == "apple" else s, l, 0)
3

You can simplify s+1 if i == "apple" else s part to just s + (i == "apple"), but I think implicit bool => int conversions are cryptic. But using reduce for this job is cryptic anyway :).

Upvotes: 2

Felix Kling
Felix Kling

Reputation: 817208

Yes it is:

reduce(lambda x,y: x + (y == 'apple'), l, 0)

But as you mentioned yourself, there is no need to use reduce here. It is likely that it will be slower than any other counting method and the intention is not immediately clear.

Upvotes: 6

Dogbert
Dogbert

Reputation: 222428

>>> l
[1, 'apple', 2, 'apple', 'apple']
>>> reduce(lambda x, y: x + (1 if y == 'apple' else 0), l, 0)
3

Upvotes: 2

Related Questions