Python(八)語法 函數語言程式設計(map/reduce/filter/sorted)
map
map()
函式接收兩個引數,一個是函式,一個是Iterable
,map
將傳入的函式依次作用到序列的每個元素,並把結果作為新的Iterator
返回。,簡單點說就是讓每個元素執行函式,如下對L中每個元素求平方
>>> def f(x): ... return x*x ... >>> L=[1,2,3,4,5] >>> r=map(f,L) >>> r <map object at 0x00000000029105F8> >>> list(r) [1, 4, 9, 16, 25] >>>
map()
傳入的第一個引數是f
,即函式物件本身。由於結果r
是一個Iterator
,Iterator
是惰性序列,因此通過list()
函式讓它把整個序列都計算出來並返回一個list。
map()
作為高階函式,事實上它把運算規則抽象了,因此,我們不但可以計算簡單的f(x)=x2,還可以計算任意複雜的函式,比如,把這個list所有數字轉為字串
>>> list(map(str,L))
['1', '2', '3', '4', '5']
reduce
reduce
把一個函式作用在一個序列[x1, x2, x3, ...]
上,這個函式必須接收兩個引數,reduce
把結果繼續和序列的下一個元素做累積計算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
比方說對一個序列求和,就可以用reduce
實現:
>>> from functools import reduce
>>> def add(x, y):
... return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25
filter
Python內建的filter()
函式用於過濾序列。
和map()
類似,filter()
也接收一個函式和一個序列。和map()
filter()
把傳入的函式依次作用於每個元素,然後根據返回值是True
還是False
決定保留還是丟棄該元素。
例如,在一個list中,刪掉偶數,只保留奇數,可以這麼寫:
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 結果: [1, 5, 9, 15]
把一個序列中的空字串刪掉,可以這麼寫:
def not_empty(s):
return s and s.strip()
list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
# 結果: ['A', 'B', 'C']
可見用filter()
這個高階函式,關鍵在於正確實現一個“篩選”函式。
注意到filter()
函式返回的是一個Iterator
,也就是一個惰性序列,所以要強迫filter()
完成計算結果,需要用list()
函式獲得所有結果並返回list。
排序演算法
排序也是在程式中經常用到的演算法。無論使用氣泡排序還是快速排序,排序的核心是比較兩個元素的大小。如果是數字,我們可以直接比較,但如果是字串或者兩個dict呢?直接比較數學上的大小是沒有意義的,因此,比較的過程必須通過函式抽象出來。
Python內建的sorted()
函式就可以對list進行排序:
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
此外,sorted()
函式也是一個高階函式,它還可以接收一個key
函式來實現自定義的排序,例如按絕對值大小排序:
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
key指定的函式將作用於list的每一個元素上,並根據key函式返回的結果進行排序。對比原始的list和經過key=abs
處理過的list:
list = [36, 5, -12, 9, -21]
keys = [36, 5, 12, 9, 21]
然後sorted()
函式按照keys進行排序,並按照對應關係返回list相應的元素:
keys排序結果 => [5, 9, 12, 21, 36]
| | | | |
最終結果 => [5, 9, -12, -21, 36]
我們再看一個字串排序的例子:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
預設情況下,對字串排序,是按照ASCII的大小比較的,由於'Z' < 'a'
,結果,大寫字母Z
會排在小寫字母a
的前面。
現在,我們提出排序應該忽略大小寫,按照字母序排序。要實現這個演算法,不必對現有程式碼大加改動,只要我們能用一個key函式把字串對映為忽略大小寫排序即可。忽略大小寫來比較兩個字串,實際上就是先把字串都變成大寫(或者都變成小寫),再比較。
這樣,我們給sorted
傳入key函式,即可實現忽略大小寫的排序:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
要進行反向排序,不必改動key函式,可以傳入第三個引數reverse=True
:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
從上述例子可以看出,高階函式的抽象能力是非常強大的,而且,核心程式碼可以保持得非常簡潔。
假設我們用一組tuple表示學生名字和成績:
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
按名字排序
# -*- coding: utf-8 -*-
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return t[0]
L2 = sorted(L, key=by_name)
print(L2)
[('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]