Question

I was trying to understand how python reduce built-in method works, so was trying some easy samples I can think of. But here is an example I don't quite understand, I'll be really appreciate if someone can give me some hints here.

So I have an array which has several prime numbers like this

>>> arr
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199]

And I try to use reduce function like this

>>> reduce(lambda x, y: is_prime(x) and is_prime(y), arr)
False

I don't quite understand why the answer here is False instead of True as I am just anding all the answer of is_prime and all the numbers in the array is prime which would return True for every is_prime.

I also checked that every number in the array actually returns True for my is_prime()

>>> for n in arr:
...     if not is_prime(n):
...         print n
...
>>>

I must have missing something here, could anyone help? Thanks.

Was it helpful?

Solution

Think about the values you're reducing one by one:

>>> reduce(lambda x,y: isprime(x) and isprime(y), [2])
2

Only one element, so reduce gives us the first.

>>> reduce(lambda x,y: isprime(x) and isprime(y), [2, 3])
True

Makes sense: both are prime.

>>> reduce(lambda x,y: isprime(x) and isprime(y), [2, 3, 5])
False

This one seems weird, but it's because you're actually calling

isprime(True) and isprime(5)

because True is the last value, and True has an int value of 1:

>>> int(True)
1

reduce != all.

OTHER TIPS

The result of

is_prime(x) and is_prime(y)

will be a boolean, and result of the current expression will be fed to the lambda function's x in the next iteration.

So, if any of the is_prime calls return False, the entire result will become False. Because

First iteration:

(Default Value & First Value)

Second iteration onwards:

(Previous Result & Current Value)

Since it is a series of and operations, if any of them is False, the entire expression will be evaluated to False

The two-argument function that is passed to reduce() is supposed to return a value that has the same type as the inputs, "reducing" two values to one value; reduce() takes care to apply the function repeatedly, reducing the whole input iterable to a single value.

Classic example: sum of the inputs using lambda x,y:x+y.

If you want the result to be true if every number in the list is prime, you can use the built-in all() function:

they_are_all_primes=all((is_prime(x) for x in [2,3,5])) 

The first parameter(x) in the lambda is the accumulated value and the second(y) is the iterated value. Try:

reduce(lambda x, y: x and is_prime(y), arr, True)

So x will be replaced by the accumulated value starting by True (the initial accumulated value), so True and is_prime(2) = True, so True is passed to the next iteration....

Experimenting checking if all are odd numbers:

>>> arr = [3, 5, 7, 11, 15]
>>> reduce(lambda x, y: x and y%2!=0, arr, True)
True

Now I will define a function to print the intermediate accumulated values:

>>> def xxx(y):
...    print y
...    return y
...
>>> reduce(lambda x, y: xxx(x) and y%2!=0, arr, True)
True
True
True
True
True
True
>>> arr = [3, 5, 7, 12, 15]
>>> reduce(lambda x, y: xxx(x) and y%2!=0, arr, True)
True
True
True
True
False
False
>>>

It will be more clear naming the variables like this:

reduce(lambda accumulated, number: accumulated and is_prime(number), arr, True)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top