Python中的lambda、map、filter、reduce、zip
lambda
lambda是匿名函數,也就是沒有名字的函數。lambda的語法非常簡單:
下面是一個lambda表達式的簡單例子:
註意:我們可以把lambda表達式賦值給一個變量,然後通過這個變量來使用它。
>>> my_sum = lambda x, y: x+y
>>> my_sum(1, 2)
3
下圖是定義lambda表達式和定義一個普通函數的對比:
註意:
使用lambda表達式並不能提高代碼的運行效率,它只能讓你的代碼看起來簡潔一些。
map
map()
接收兩個參數func
(函數)和seq
(序列,例如list)。如下圖:
map()
func
應用於序列seq
中的所有元素。在Python3之前,map()
返回一個列表,列表中的每個元素都是將列表或元組“seq
”中的相應元素傳入函數func
返回的結果。Python 3中map()
返回一個叠代器。
因為map()
需要一個函數作為參數,所以可以搭配lambda表達式很方便的實現各種需求:
- 例子1–將一個列表裏面的每個數字都加100:
>>> l = [11, 22, 33, 44, 55]
>>> list(map(lambda x:x+100, l))
[111, 122, 133, 144, 155]
- 例子2–
使用map
就相當於使用了一個for循環,我們完全可以自己定義一個my_map
def my_map(func, seq):
result = []
for i in seq:
result.append(func(i))
return result
測試一下我們自己的my_map
函數:
>>> def my_map(func, seq):
... result = []
... for i in seq:
... result.append(func(i))
... return result
...
>>> l = [11, 22, 33, 44, 55]
>>> list(my_map(lambda x:x+100, l))
[111, 122, 133, 144, 155]
我們自定義的my_map
函數的效果和內置的map
函數一樣。
當然在Python3中,map
函數返回的是一個叠代器,所以我們也需要讓我們的my_map
函數返回一個叠代器:
def my_map(func, seq):
for i in seq:
yield func(i)
測試一下:
>>> def my_map(func, seq):
... for i in seq:
... yield func(i)
...
>>> l = [11, 22, 33, 44, 55]
>>> list(my_map(lambda x:x+100, l))
[111, 122, 133, 144, 155]
與我們自己定義的my_map
函數相比,由於map
是內置的因此它始終可用,並且始終以相同的方式工作。它也具有一些性能優勢,通常會比手動編寫的for循環更快。當然內置的map
還有一些高級用法:
例如,可以給map函數傳入多個序列參數,它將並行的序列作為不同參數傳入函數:
拿pow(arg1, arg2)
函數舉例,
>>> pow(2, 10)
1024
>>> pow(3, 11)
177147
>>> pow(4, 12)
16777216
>>> list(map(pow, [2, 3, 4], [10, 11, 12]))
[1024, 177147, 16777216]
pow(arg1, arg2)函數接收兩個參數arg1和arg2,map(pow, [2, 3, 4], [10, 11, 12])就會並行從[2, 3, 4]和[10, 11, 12]中取出元素,傳入到pow中。
還有一個例子:
>>> from operator import add
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> list(map(add, x, y))
[5, 7, 9]
調用map
函數類似於列表推導式
,但是列表推導式
是對每個元素做表達式運算,而map
對每個元素都會應用一次函數調用。也只有在map
中使用內置函數時,才可能比列表推導式
速度更快。
filter
filter
函數和map
函數一樣也是接收兩個參數func
(函數)和seq
(序列,如list),如下圖:
filter
函數類似實現了一個過濾功能,它過濾序列中的所有元素,返回那些傳入func
後返回True
的元素。也就是說filter函數的第一個參數func
必須返回一個布爾值,即True或者False。
下面這個例子,是使用filter
從一個列表中過濾出大於33的數:
>>> l = [30, 11, 77, 8, 25, 65, 4]
>>> list(filter(lambda x: x>33, l))
[77, 65]
利用filter()
還可以用來判斷兩個列表的交集:
>>> x = [1, 2, 3, 5, 6]
>>> y = [2, 3, 4, 6, 7]
>>> list(filter(lambda a: a in y, x))
[2, 3, 6]
reduce
註意:Python3中reduce
移到了functools模塊中,你可以用過from functools import reduce
來使用它。
reduce
同樣是接收兩個參數:func
(函數)和seq
(序列,如list),如下圖:
reduce
最後返回的不是一個叠代器,它返回一個值。
reduce
首先將序列中的前兩個元素,傳入func
中,再將得到的結果和第三個元素一起傳入func
,…,這樣一直計算到最後,得到一個值,把它作為reduce
的結果返回。
原理類似於下圖:
看一下運行結果:
>>> from functools import reduce
>>> reduce(lambda x,y:x+y, [1, 2, 3, 4])
10
再來練習一下,使用reduce求1~100的和:
>>> from functools import reduce
>>> reduce(lambda x,y:x+y, range(1, 101))
5050
三元運算
三元運算
(三目運算)在Python中也叫條件表達式。三元運算的語法非常簡單,主要是基於True/False的判斷。如下圖:
使用它就可以用簡單的一行快速判斷,而不再需要使用復雜的多行if
語句。 大多數時候情況下使用三元運算能夠讓你的代碼更清晰。
三元運算
配合lambda表達式
和reduce
,求列表裏面值最大的元素:
>>> from functools import reduce
>>> l = [30, 11, 77, 8, 25, 65, 4]
>>> reduce(lambda x,y: x if x > y else y, l)
77
再來一個,三元運算
配合lambda表達式
和map
的例子:
將一個列表裏面的奇數加100:
>>> l = [30, 11, 77, 8, 25, 65, 4]
>>> list(map(lambda x: x+100 if x%2 else x, l))
[30, 111, 177, 8, 125, 165, 4]
zip
zip
函數接收一個或多個可叠代對象作為參數,最後返回一個叠代器:
>>> x = ["a", "b", "c"]
>>> y = [1, 2, 3]
>>> a = list(zip(x, y)) # 合包
>>> a
[(‘a‘, 1), (‘b‘, 2), (‘c‘, 3)]
>>> b =list(zip(*a)) # 解包
>>> b
[(‘a‘, ‘b‘, ‘c‘), (1, 2, 3)]
zip(x, y)
會生成一個可返回元組 (m, n)
的叠代器,其中m來自x,n來自y。 一旦其中某個序列叠代結束,叠代就宣告結束。 因此叠代長度跟參數中最短的那個序列長度一致。
>>> x = [1, 3, 5, 7, 9]
>>> y = [2, 4, 6, 8]
>>> for m, n in zip(x, y):
... print(m, n)
...
1 2
3 4
5 6
7 8
如果上面不是你想要的效果,那麽你還可以使用 itertools.zip_longest()
函數來代替這個例子中的zip
。
>>> from itertools import zip_longest
>>> x = [1, 3, 5, 7, 9]
>>> y = [2, 4, 6, 8]
>>> for m, n in zip_longest(x, y):
... print(m, n)
...
1 2
3 4
5 6
7 8
9 None
zip
其他常見應用:
>>> keys = ["name", "age", "salary"]
>>> values = ["Andy", 18, 50]
>>> d = dict(zip(keys, values))
>>> d
{‘name‘: ‘Andy‘, ‘age‘: 18, ‘salary‘: 50}
Python中的lambda、map、filter、reduce、zip