簡體   English   中英

如何在 Python 3 中使用 filter、map 和 reduce

[英]How to use filter, map, and reduce in Python 3

filtermapreduce在 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 2 和 3 的空閑會話並排

您可以閱讀Python 3.0 中的新增功能中的更改。 當您從 2.x 移動到 3.x 時,您應該仔細閱讀它,因為發生了很多變化。

這里的整個答案是文檔中的引用。

視圖和迭代器而不是列表

一些著名的 API 不再返回列表:

  • [...]
  • map()filter()返回迭代器。 如果你真的需要一個列表,一個快速的解決方法是例如list(map(...)) ,但更好的解決方法通常是使用列表理解(尤其是當原始代碼使用 lambda 時),或者重寫代碼使其不根本不需要清單。 特別棘手的是map()為函數的副作用而調用; 正確的轉換是使用常規的for循環(因為創建列表只會浪費)。
  • [...]

內置函數

  • [...]
  • 刪除了reduce() 如果確實需要,請使用functools.reduce() 但是,在 99% 的情況下,顯式for循環更具可讀性。
  • [...]

mapfilter的功能被有意更改為返回迭代器,reduce 從內置中刪除並放置在functools.reduce

因此,對於filtermap ,您可以使用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:

  • 在這里,它們都返回給定數字的立方體。 但是,在使用 def 時,我們需要定義一個名為 cube 的函數,並且需要向它傳遞一個值。 執行后,我們還需要使用 return 關鍵字從調用函數的位置返回結果。

使用 Lambda:

  • Lambda 定義不包含“return”語句,它始終包含返回的表達式。 我們還可以將 lambda 定義放在需要函數的任何地方,而我們根本不必將其分配給變量。 這就是 lambda 函數的簡單性。

Lambda 函數可以與filter()map()reduce()等內置函數一起使用。

lambda() 和 filter()

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]

lambda() 和 map()

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 個元素,在第一個元素之前,如果提供。

lambda() 與 reduce()

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM