[英]How to use filter, map, and reduce in Python 3
filter
、 map
和reduce
在 Python 2 中完美運行。 下面是一個例子:
>>> 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
但是在 Python 3 中,我收到以下輸出:
>>> 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
如果有人能向我解釋為什么會這樣,我將不勝感激。
進一步清晰的代碼截圖:
您可以閱讀Python 3.0 中的新增功能中的更改。 當您從 2.x 移動到 3.x 時,您應該仔細閱讀它,因為發生了很多變化。
這里的整個答案是文檔中的引用。
一些著名的 API 不再返回列表:
- [...]
- 刪除了
reduce()
。 如果確實需要,請使用functools.reduce()
; 但是,在 99% 的情況下,顯式for
循環更具可讀性。- [...]
map
和filter
的功能被有意更改為返回迭代器,reduce 從內置中刪除並放置在functools.reduce
。
因此,對於filter
和map
,您可以使用list()
將它們包裝起來以查看結果,就像您之前所做的那樣。
>>> 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
>>>
現在的建議是用生成器表達式或列表推導式替換 map 和 filter 的使用。 例子:
>>> 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]
>>>
他們說 for 循環在 99% 的時間里比 reduce 更容易閱讀,但我還是堅持使用functools.reduce
。
編輯:99% 的數字是直接從 Guido van Rossum 撰寫的Python 3.0 的新增功能頁面中提取的。
作為其他答案的附錄,這聽起來像是上下文管理器的一個很好的用例,它將這些函數的名稱重新映射到返回列表並在全局命名空間中引入reduce
函數的名稱。
快速實現可能如下所示:
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 noiters(map):
from operator import add
print(reduce(add, range(1, 20)))
print(map(int, ['1', '2']))
哪個打印:
190
[1, 2]
只有我的 2 美分 :-)
由於已從 Python3 的內置函數中刪除了reduce
方法,請不要忘記在代碼中導入functools
。 請看下面的代碼片段。
import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)
map、filter 和 reduce 的優點之一是當您將它們“鏈接”在一起以執行復雜的操作時,它們變得清晰易讀。 但是,內置語法不清晰,而且都是“倒退”的。 所以,我建議使用PyFunctional
包( https://pypi.org/project/PyFunctional/ )。 這是兩者的比較:
flight_destinations_dict = {'NY': {'London', 'Rome'}, 'Berlin': {'NY'}}
PyFunctional 版本
非常清晰的語法。 你可以說:
“我有一系列航班目的地。如果城市在字典值中,我想從中獲取字典鍵。最后,過濾掉我在此過程中創建的空列表。”
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 != []) \
默認 Python 版本
都是倒退。 你需要說:
“好的,所以,有一個列表。我想從中過濾空列表。為什么?因為如果城市在 dict 值中,我首先得到了 dict 鍵。哦,我正在做的列表是 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())
)
)
以下是 Filter、map 和 reduce 函數的示例。
數字 = [10,11,12,22,34,43,54,34,67,87,88,98,99,87,44,66]
//篩選
奇數 = 列表(過濾器(lambda x:x%2 != 0,數字))
打印(奇數)
//地圖
multiplyOf2 = list(map(lambda x: x*2, numbers))
打印(multiplyOf2)
//降低
reduce 函數由於不常用,已從 Python 3 的內置函數中刪除。它在 functools 模塊中仍然可用,因此您可以執行以下操作:
從 functools 導入減少
sumOfNumbers = reduce(lambda x,y: x+y, numbers)
打印(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
它按原樣工作。 要獲取地圖使用 * 或列表的輸出
嘗試理解普通的 def 定義函數和 lambda 函數之間的區別。 這是一個返回給定值的立方體的程序:
# Python code to illustrate cube of a number
# showing difference between def() and lambda().
def cube(y):
return y*y*y
lambda_cube = lambda y: y*y*y
# using the normally
# defined function
print(cube(5))
# using the lamda function
print(lambda_cube(5))
輸出:
125
125
不使用 Lambda:
使用 Lambda:
Lambda 函數可以與filter()
、 map()
和reduce()
等內置函數一起使用。
Python 中的filter()
函數接受一個函數和一個列表作為參數。 這提供了一種優雅的方法來過濾掉序列“序列”的所有元素,函數返回True
。
my_list = [1, 5, 4, 6, 8, 11, 3, 12]
new_list = list(filter(lambda x: (x%2 == 0) , my_list))
print(new_list)
ages = [13, 90, 17, 59, 21, 60, 5]
adults = list(filter(lambda age: age>18, ages))
print(adults) # above 18 yrs
輸出:
[4, 6, 8, 12]
[90, 59, 21, 60]
Python 中的map()
函數接受一個函數和一個列表作為參數。 該函數使用 lambda 函數和一個列表調用,並返回一個新列表,其中包含該函數為每個項目返回的所有 lambda 修改項。
my_list = [1, 5, 4, 6, 8, 11, 3, 12]
new_list = list(map(lambda x: x * 2 , my_list))
print(new_list)
cities = ['novi sad', 'ljubljana', 'london', 'new york', 'paris']
# change all city names
# to upper case and return the same
uppered_cities = list(map(lambda city: str.upper(city), cities))
print(uppered_cities)
輸出:
[2, 10, 8, 12, 16, 22, 6, 24]
['NOVI SAD', 'LJUBLJANA', 'LONDON', 'NEW YORK', 'PARIS']
reduce()
工作方式與map()
和filter()
。 它不會根據我們傳遞的function
和可迭代對象返回新列表。 相反,它返回單個值。
此外,在 Python 3 中, reduce()
不再是內置函數,它可以在functools
模塊中找到。
語法是:
reduce(function, sequence[, initial])
reduce()
通過調用我們為序列中的前兩項傳遞的function
工作。 function
返回的結果與下一個(在本例中為第三個)元素一起用於對function
另一個調用。
可選參數initial
當存在時,在此“循環”的開頭使用,第一次調用function
的第一個元素。 在某種程度上, initial
元素是第 0 個元素,在第一個元素之前,如果提供。
Python 中的 reduce() 函數接受一個函數和一個列表作為參數。 使用 lambda 函數和可迭代函數調用該函數,並返回一個新的縮減結果。 這對可迭代的對執行重復操作。
from functools import reduce
my_list = [1, 1, 2, 3, 5, 8, 13, 21, 34]
sum = reduce((lambda x, y: x + y), my_list)
print(sum) # sum of a list
print("With an initial value: " + str(reduce(lambda x, y: x + y, my_list, 100)))
88
With an initial value: 188
這些函數是便利函數。 它們在那里,因此您可以避免編寫更繁瑣的代碼,但避免同時使用它們和 lambda 表達式,因為“您可以”,因為它通常會導致難以維護的難以辨認的代碼。 僅當您在查看函數或 lambda 表達式時就完全清楚發生了什么時才使用它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.