# Difficulties understanding reduce function in context

https://app.dataquest.io/m/263/functional-programming/7/the-reduce-function

My Code:

``````lines = read('example_log.txt')
ip_addresses = list(map(lambda x: x.split(), lines))
filtered_ips = list(filter(lambda x: int(x.split('.')) <= 20, ip_addresses))
count_all = reduce(lambda x, _: 2 if isinstance(x, str) else x + 1, lines)
``````

Can someone explain me why the lambda function of variable `count_all` should return `2` if `isinstance(x, str)` ?

3 Likes

This is explained in the given screen, from the sentence below, until the end of the learn section.

Another important aspect of reduce is that the lambda function does not necessarily need to return a value that is of the same type as the inputs

Let’s see a simpler example and explain what it is doing

``````>>> ip_head = [
... '200.155.108.44',
...  '36.139.255.202',
...  '50.112.115.219',
...  '204.132.56.4',
...  '233.154.7.24'
... ]
``````

The goal is to count how many elements `ip_head` has, using `reduce`.

``````>>> reduce(lambda x, _: 2 if isinstance(x, str) else x + 1, ip_head)
5
``````

Let’s see what this is doing. We’ll begin by analyzing the function `lambda x,_: 2 if isinstance(x, str) else x + 1`.

Let’s rewrite it as a regular function:

``````>>> def sum_if_not_string(x,y):
...     if isinstance(x, str):
...         return 2
...     else:
...         return x+1
``````

This function returns `2` if the first argument is a string, otherwise it tries to add `1` to it.

``````>>> sum_if_not_string("Epstein didn't kill himself", 17)
2
>>> sum_if_not_string(20, 17)
21
``````

Let’s see the behavior when we pass `sum_if_not_string,ip_head` to reduce.

``````>>> reduce(sum_if_not_string, ip_head)
5
``````

It’s the same function, so we get the same behavior. Now that we’ve abstracted away the function, let’s focus on what it is doing with reduce.

First, it takes is as parameters the first two entries of `ip_head`. In other words, it’s calling `sum_if_not_string('200.155.108.44', '36.139.255.202')`. This returns `2` because the first argument is a string.

Next, because that’s how `reduce` works, the result we got above (`2`), and the third element of `ip_head`, are passed to `sum_if_not_string`. In other words, it calls `sum_if_not_string(2, '50.112.115.219)`. This returns `3` because the first argument is not a string.

After this it calls `3` together with the fourth element of `ip_head`, returning `4`. And to finalize, it runs `sum_if_not_string(4, '233.154.7.24')`, resulting in `5`.

I hope this helps.

7 Likes

Great example, I got it thanks!

1 Like

This was a great breakdown!

1 Like

What if list has only one element?

You can just try it to get a sense of what happens. In any case, from the documentation:

Apply function of two arguments cumulatively to the items of iterable , from left to right, so as to reduce the iterable to a single value. For example, `reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])` calculates `((((1+2)+3)+4)+5)` . The left argument, x , is the accumulated value and the right argument, y , is the update value from the iterable . If the optional initializer is present, it is placed before the items of the iterable in the calculation, and serves as a default when the iterable is empty. If initializer is not given and iterable contains only one item, the first item is returned.

2 Likes

Thank you so much !!

1 Like