Reduce() after filter() in Python? - python

I have question about two functions in python: reduce() and filter().
Can we use reduce() after filter()?
I used boston datasets in sklearn.
x = load_boston()
x_target = x.target
xx = filter(lambda x: x > 20, x_target)
And it's working fine.
Next I want use reduce() function to sum up values in xx.
from functools import reduce
xxx = reduce(lambda x,y: x+y, xx)
I got error:
TypeError Traceback (most recent call last)
<ipython-input-64-062fcc861672> in <module>()
1 from functools import reduce
----> 2 xxx = reduce(lambda x,y: x+y, xx)
TypeError: reduce() of empty sequence with no initial value
Any suggestions?

Yes, you can use a filter() object in reduce() just fine:
>>> from functools import reduce
>>> values = range(10, 30)
>>> filtered = filter(lambda x: x > 20, values)
>>> reduce(lambda x, y: x + y, filtered)
225
However, a filter() object is an iterator; it will yield filtered values on demand, and when it reaches the end won't yield anything else. So you need to make sure you don't empty it before you pass it to reduce():
>>> filtered = filter(lambda x: x > 20, values)
>>> filtered
<filter object at 0x10ee64ac8>
>>> list(filtered)
[21, 22, 23, 24, 25, 26, 27, 28, 29]
>>> reduce(lambda x, y: x + y, filtered)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: reduce() of empty sequence with no initial value
Re-create the filter() object when you need to re-use it in multiple places.

That means the filter function returns an empty list over your list. Here you have an example:
sample = [2,3,4,5,6,7,8]
filter(lambda x: x%2 == 0, sample)
>>> [2, 4, 6, 8]
reduce(lambda x,y: x+y, filter(lambda x: x%2 == 0, sample))
>>> 20
So, your code should work.
This is python 2.7. Should be different in python 3+
EDIT: with python3
from functools import reduce
sample = [2,3,4,5,6,7,8]
f = filter(lambda x: x%2 == 0, sample)
reduce(lambda x,y: x+y, f)
>>> 20
Works the same way ; )

Related

Python weird answer (tuple and list with count function)

This is the code given below.
k = [1, 8, 15]
g = (x for x in k if k.count(x) > 0)
k = [2, 8, 22]
print(list(g))
I am getting the output as [8] but it should be [1,8,15], right? since each element is present at least once.
Any plausible explanation for the answer?
That's a generator expression. It creates a generator, not a tuple.
Exactly one part of a generator expression is evaluated at genexp creation time. It's this part:
g = (x for x in k if k.count(x)>0)
# ^
Everything else, including this part:
g = (x for x in k if k.count(x)>0)
# ^
is evaluated lazily.
That means the k you're looping over is the original k, but the k you're calling count on is the new k.
Here's a trick to see which k uses the original/modified list by printing x and k in the generator expression:
1st k refers to the original list:
>>> k = [1,8,15]
>>> g = (x for x in k if (print(x) == None and k.count(x)>0))
>>> k = [2,8,22]
>>> list(g)
1
8
15
2nd k refers to the modified list:
>>> k = [1,8,15]
>>> g = (x for x in k if (print(k) == None and k.count(x)>0))
>>> k = [2,8,22]
>>> list(g)
[2, 8, 22]
[2, 8, 22]
[2, 8, 22]
Debugging trick similar to Shawn's:
def p(label, x):
print(label, x)
return x
k = [1,8,15]
g = (x for x in p('iterate over', k) if p('count in', k).count(x)>0)
k = [2,8,22]
print('between generator construction and consumption')
list(g)
Output (Try it online!):
iterate over [1, 8, 15]
between generator construction and consumption
count in [2, 8, 22]
count in [2, 8, 22]
count in [2, 8, 22]
Generator is fetch on process memory,work like lazy operator so that happen
"""""for x in [1,8,15]:
if [2,8,22].count(x): """"
That is how interpreter fetch values.
Refer this tweet for more understand:
https://twitter.com/nedbat/status/1503735148378001410?t=lJLT482Vmt19cBNuP-PAWQ&s=19
https://twitter.com/driscollis/status/1503366898234404866?t=OgCM0E1rzWAEQOOziO9uqA&s=19
#Learning with hope

High Order Map Function with Lambda Expression Python

I'm trying to write a higher order function that will take 2 lambda expressions and a list and will return the result. I have my code below.
#Square
square = lambda x:x ** 2
#Mod_2
mod_2 = lambda x:x % 2
def map(f,x):
return f(x)
It looks very simple, and should be. This is the error I get:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "main.py", line 8, in map
return f(x)
File "main.py", line 2, in <lambda>
square = lambda x:x ** 2
TypeError: unsupported operand type(s) for ** or pow(): 'list' and 'int'
Here's what the results should be:
>>> map(square, [1, 2, 3, 4])
[1, 4, 9, 16]
>>> map(square, [])
[]
>>> map(mod_2, range(1, 11))
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
This is NOT homework, and is simply and way to understand higher order functions better. Also, this is not a repeat of any other submission because this is fixing MY code, not how to do the problem itself. If it needs rethinking, please reply and tell me how. Thank you!
Use a list comprehension:
def map(f,x):
return [f(i) for i in x]
You can use a lambda here too:
map = lambda f, x: [f(i) for i in x]
Or just use the map() built-in.
map() is a built-in function. Why are you redefining it? Delete def map().
#Square
square = lambda x: x**2
#Mod_2
mod_2 = lambda x:x % 2
r1 = list(map(square, [1, 2, 3, 4]))
r2 = list(map(mod_2, range(1, 11)))

Iterating over a list of integers using map and using a list of functions

Hi guys Im trying to write a code that uses a list of functions and a list of integers and only returns the ones that have at least 1 true in the list of functions like so:
tuple(lambda func,data:filter(lambda x:map(lambda y:y(x)==true,func),data))
func=(lambda x: x>3,lambda x: x%2==0)
data=(1,2,3,4,5,6,7,8,9,10)
so the list should return
4,6,8,10
but instead it returns the entire list,does anybody knows why?
P.S I know it can be done very easily in a different way, but Its a lambda exercise.
You can use an expression like the following:
tuple(filter(lambda x: any(filter(lambda f: f(x), func)), data))
So,
In [17]: func=(lambda x: x>3,lambda x: x%2==0)
...: data=(1,2,3,4,5,6,7,8,9,10)
...:
...:
In [18]: tuple(filter(lambda x: any(filter(lambda f: f(x), func)), data))
Out[18]: (2, 4, 5, 6, 7, 8, 9, 10)
Also note, your expression raises a TypeError, so I don't know what you mean about it returning the whole list.
It would probably be more readable to use something like:
In [23]: tuple(
...: x for x in data
...: if any(f(x) for f in func)
...: )
Out[23]: (2, 4, 5, 6, 7, 8, 9, 10)
Or without any (a ridiculous constraint)
In [29]: tuple(filter(lambda x: tuple(filter(None, map(lambda f: f(x), func))), data))
Out[29]: (2, 4, 5, 6, 7, 8, 9, 10)
It's more Pythonic to map these functions using list comprehensions:
data = range(1, 11)
funcs = (lambda x: x > 3, lambda x: x % 2 == 0)
new_data = [x for x in l if all(f(x) for f in funcs)]
# new_data == [4, 6, 8, 10]

filter not returning the constructed or matched list [duplicate]

filter, map, and reduce work perfectly in Python 2. Here is an example:
>>> def f(x):
return x % 2 != 0 and x % 3 != 0
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x):
return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> def add(x,y):
return x+y
>>> reduce(add, range(1, 11))
55
But in Python 3, I receive the following outputs:
>>> filter(f, range(2, 25))
<filter object at 0x0000000002C14908>
>>> map(cube, range(1, 11))
<map object at 0x0000000002C82B70>
>>> reduce(add, range(1, 11))
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
reduce(add, range(1, 11))
NameError: name 'reduce' is not defined
I would appreciate if someone could explain to me why this is.
Screenshot of code for further clarity:
You can read about the changes in What's New In Python 3.0. You should read it thoroughly when you move from 2.x to 3.x since a lot has been changed.
The whole answer here are quotes from the documentation.
Views And Iterators Instead Of Lists
Some well-known APIs no longer return lists:
[...]
map() and filter() return iterators. If you really need a list, a quick fix is e.g. list(map(...)), but a better fix is often to use a list comprehension (especially when the original code uses lambda), or rewriting the code so it doesn’t need a list at all. Particularly tricky is map() invoked for the side effects of the function; the correct transformation is to use a regular for loop (since creating a list would just be wasteful).
[...]
Builtins
[...]
Removed reduce(). Use functools.reduce() if you really need it; however, 99 percent of the time an explicit for loop is more readable.
[...]
The functionality of map and filter was intentionally changed to return iterators, and reduce was removed from being a built-in and placed in functools.reduce.
So, for filter and map, you can wrap them with list() to see the results like you did before.
>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> list(filter(f, range(2, 25)))
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> list(map(cube, range(1, 11)))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> import functools
>>> def add(x,y): return x+y
...
>>> functools.reduce(add, range(1, 11))
55
>>>
The recommendation now is that you replace your usage of map and filter with generators expressions or list comprehensions. Example:
>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> [i for i in range(2, 25) if f(i)]
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> [cube(i) for i in range(1, 11)]
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>>
They say that for loops are 99 percent of the time easier to read than reduce, but I'd just stick with functools.reduce.
Edit: The 99 percent figure is pulled directly from the What’s New In Python 3.0 page authored by Guido van Rossum.
As an addendum to the other answers, this sounds like a fine use-case for a context manager that will re-map the names of these functions to ones which return a list and introduce reduce in the global namespace.
A quick implementation might look like this:
from contextlib import contextmanager
#contextmanager
def noiters(*funcs):
if not funcs:
funcs = [map, filter, zip] # etc
from functools import reduce
globals()[reduce.__name__] = reduce
for func in funcs:
globals()[func.__name__] = lambda *ar, func = func, **kwar: list(func(*ar, **kwar))
try:
yield
finally:
del globals()[reduce.__name__]
for func in funcs: globals()[func.__name__] = func
With a usage that looks like this:
with noiters(map):
from operator import add
print(reduce(add, range(1, 20)))
print(map(int, ['1', '2']))
Which prints:
190
[1, 2]
Just my 2 cents :-)
Since the reduce method has been removed from the built in function from Python3, don't forget to import the functools in your code. Please look at the code snippet below.
import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)
One of the advantages of map, filter and reduce is how legible they become when you "chain" them together to do something complex. However, the built-in syntax isn't legible and is all "backwards". So, I suggest using the PyFunctional package (https://pypi.org/project/PyFunctional/).
Here's a comparison of the two:
flight_destinations_dict = {'NY': {'London', 'Rome'}, 'Berlin': {'NY'}}
PyFunctional version
Very legible syntax. You can say:
"I have a sequence of flight destinations. Out of which I want to get
the dict key if city is in the dict values. Finally, filter out the
empty lists I created in the process."
from functional import seq # PyFunctional package to allow easier syntax
def find_return_flights_PYFUNCTIONAL_SYNTAX(city, flight_destinations_dict):
return seq(flight_destinations_dict.items()) \
.map(lambda x: x[0] if city in x[1] else []) \
.filter(lambda x: x != []) \
Default Python version
It's all backwards. You need to say:
"OK, so, there's a list. I want to filter empty lists out of it. Why?
Because I first got the dict key if the city was in the dict values.
Oh, the list I'm doing this to is flight_destinations_dict."
def find_return_flights_DEFAULT_SYNTAX(city, flight_destinations_dict):
return list(
filter(lambda x: x != [],
map(lambda x: x[0] if city in x[1] else [], flight_destinations_dict.items())
)
)
Here are the examples of Filter, map and reduce functions.
numbers = [10,11,12,22,34,43,54,34,67,87,88,98,99,87,44,66]
//Filter
oddNumbers = list(filter(lambda x: x%2 != 0, numbers))
print(oddNumbers)
//Map
multiplyOf2 = list(map(lambda x: x*2, numbers))
print(multiplyOf2)
//Reduce
The reduce function, since it is not commonly used, was removed from the built-in functions in Python 3. It is still available in the functools module, so you can do:
from functools import reduce
sumOfNumbers = reduce(lambda x,y: x+y, numbers)
print(sumOfNumbers)
from functools import reduce
def f(x):
return x % 2 != 0 and x % 3 != 0
print(*filter(f, range(2, 25)))
#[5, 7, 11, 13, 17, 19, 23]
def cube(x):
return x**3
print(*map(cube, range(1, 11)))
#[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
def add(x,y):
return x+y
reduce(add, range(1, 11))
#55
It works as is. To get the output of map use * or list

How to use filter, map, and reduce in Python 3

filter, map, and reduce work perfectly in Python 2. Here is an example:
>>> def f(x):
return x % 2 != 0 and x % 3 != 0
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x):
return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> def add(x,y):
return x+y
>>> reduce(add, range(1, 11))
55
But in Python 3, I receive the following outputs:
>>> filter(f, range(2, 25))
<filter object at 0x0000000002C14908>
>>> map(cube, range(1, 11))
<map object at 0x0000000002C82B70>
>>> reduce(add, range(1, 11))
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
reduce(add, range(1, 11))
NameError: name 'reduce' is not defined
I would appreciate if someone could explain to me why this is.
Screenshot of code for further clarity:
You can read about the changes in What's New In Python 3.0. You should read it thoroughly when you move from 2.x to 3.x since a lot has been changed.
The whole answer here are quotes from the documentation.
Views And Iterators Instead Of Lists
Some well-known APIs no longer return lists:
[...]
map() and filter() return iterators. If you really need a list, a quick fix is e.g. list(map(...)), but a better fix is often to use a list comprehension (especially when the original code uses lambda), or rewriting the code so it doesn’t need a list at all. Particularly tricky is map() invoked for the side effects of the function; the correct transformation is to use a regular for loop (since creating a list would just be wasteful).
[...]
Builtins
[...]
Removed reduce(). Use functools.reduce() if you really need it; however, 99 percent of the time an explicit for loop is more readable.
[...]
The functionality of map and filter was intentionally changed to return iterators, and reduce was removed from being a built-in and placed in functools.reduce.
So, for filter and map, you can wrap them with list() to see the results like you did before.
>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> list(filter(f, range(2, 25)))
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> list(map(cube, range(1, 11)))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> import functools
>>> def add(x,y): return x+y
...
>>> functools.reduce(add, range(1, 11))
55
>>>
The recommendation now is that you replace your usage of map and filter with generators expressions or list comprehensions. Example:
>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> [i for i in range(2, 25) if f(i)]
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> [cube(i) for i in range(1, 11)]
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>>
They say that for loops are 99 percent of the time easier to read than reduce, but I'd just stick with functools.reduce.
Edit: The 99 percent figure is pulled directly from the What’s New In Python 3.0 page authored by Guido van Rossum.
As an addendum to the other answers, this sounds like a fine use-case for a context manager that will re-map the names of these functions to ones which return a list and introduce reduce in the global namespace.
A quick implementation might look like this:
from contextlib import contextmanager
#contextmanager
def noiters(*funcs):
if not funcs:
funcs = [map, filter, zip] # etc
from functools import reduce
globals()[reduce.__name__] = reduce
for func in funcs:
globals()[func.__name__] = lambda *ar, func = func, **kwar: list(func(*ar, **kwar))
try:
yield
finally:
del globals()[reduce.__name__]
for func in funcs: globals()[func.__name__] = func
With a usage that looks like this:
with noiters(map):
from operator import add
print(reduce(add, range(1, 20)))
print(map(int, ['1', '2']))
Which prints:
190
[1, 2]
Just my 2 cents :-)
Since the reduce method has been removed from the built in function from Python3, don't forget to import the functools in your code. Please look at the code snippet below.
import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)
One of the advantages of map, filter and reduce is how legible they become when you "chain" them together to do something complex. However, the built-in syntax isn't legible and is all "backwards". So, I suggest using the PyFunctional package (https://pypi.org/project/PyFunctional/).
Here's a comparison of the two:
flight_destinations_dict = {'NY': {'London', 'Rome'}, 'Berlin': {'NY'}}
PyFunctional version
Very legible syntax. You can say:
"I have a sequence of flight destinations. Out of which I want to get
the dict key if city is in the dict values. Finally, filter out the
empty lists I created in the process."
from functional import seq # PyFunctional package to allow easier syntax
def find_return_flights_PYFUNCTIONAL_SYNTAX(city, flight_destinations_dict):
return seq(flight_destinations_dict.items()) \
.map(lambda x: x[0] if city in x[1] else []) \
.filter(lambda x: x != []) \
Default Python version
It's all backwards. You need to say:
"OK, so, there's a list. I want to filter empty lists out of it. Why?
Because I first got the dict key if the city was in the dict values.
Oh, the list I'm doing this to is flight_destinations_dict."
def find_return_flights_DEFAULT_SYNTAX(city, flight_destinations_dict):
return list(
filter(lambda x: x != [],
map(lambda x: x[0] if city in x[1] else [], flight_destinations_dict.items())
)
)
Here are the examples of Filter, map and reduce functions.
numbers = [10,11,12,22,34,43,54,34,67,87,88,98,99,87,44,66]
//Filter
oddNumbers = list(filter(lambda x: x%2 != 0, numbers))
print(oddNumbers)
//Map
multiplyOf2 = list(map(lambda x: x*2, numbers))
print(multiplyOf2)
//Reduce
The reduce function, since it is not commonly used, was removed from the built-in functions in Python 3. It is still available in the functools module, so you can do:
from functools import reduce
sumOfNumbers = reduce(lambda x,y: x+y, numbers)
print(sumOfNumbers)
from functools import reduce
def f(x):
return x % 2 != 0 and x % 3 != 0
print(*filter(f, range(2, 25)))
#[5, 7, 11, 13, 17, 19, 23]
def cube(x):
return x**3
print(*map(cube, range(1, 11)))
#[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
def add(x,y):
return x+y
reduce(add, range(1, 11))
#55
It works as is. To get the output of map use * or list

Categories

Resources