Python 提供的一些內建的函數之一:map()



Introduction

一般我們對一個 list 或是其他 sequence 裡頭的每個元素做一些計算的時候,比如說,把一個 list 裡的每個元素都乘以 10,我們會用 for loop 這樣做:

1
2
3
4
5
6
items = [1, 2, 3, 4, 5]
newitems = []
for itm in items:
newitems.append(itm*10)
newitems # [10, 20, 30, 40, 50]

而 Python 有一個內建的函數可以直接幫我們做到這件事,它就是 map(function, iterable, ...)

官方文件是這樣描述它的:

Apply function to every item of iterable and return a list of the results.

它可以將 pass-in function 在 iterable object 裡的每個元素身上,然後回傳一個 list,這個 list 包含了所有 function call results。一樣的 list,一樣乘以 10,用 map() 可以這樣做:

1
2
3
4
items = [1, 2, 3, 4, 5]
def times(x): return x * 10
list(map(times, items)) # [10, 20, 30, 40, 50]

這裡先寫了一個自定義的 function 叫做 times() ,這個 function 會將傳入的數值乘以 10 之後回傳。map(times, items)會將times() 應用在 items 裡的每個元素身上,也就是將每個元素都乘以 10 之後回傳,然後將這些回傳結果收集起來成為一個新的 list。

map() with lambda

因為 map() 需要一個傳入的函數,所以 lambda 在這裡也常常被用到。lambda 可以想像成是 Python 提供的一個簡易的 function define,用完即丟,它可以讓你實作出很簡單的 function (只處理一個運算式)。

1
2
3
4
5
lambda param1, param2, ... : expression
#equals to
def fun( param1, param2, ... ) :
return expression

回到 map(),如果是上述的範例,加入 lambda 之後,會變成這樣:

1
list(map((lambda x: x * 10), items)) # [10, 20, 30, 40, 50]

只要一行,輕輕鬆鬆簡簡單單。

而當我們繼續使用 lambda 作為 pass-in function 的時候,map() 的第二個參數可以傳入 a list of functions,來看看怎麼做:

1
2
3
4
5
6
7
8
9
10
def square(x):
return (x**2)
def cube(x):
return (x**3)
funcs = [square, cube]
for r in range(5):
value = map(lambda x: x(r), funcs)
print value

這段程式碼將 r 傳入lambda function 裡,然後再對 r 做 funcs list 裡的事,就是分別把 r 做平方和三次放運算,這是執行結果:

[0, 0]
[1, 1]
[4, 8]
[9, 27]
[16, 64]

Implementation

因為 map() 的用法和 for loop 相同,所以也可以很容易寫出一個相同功能的 function。

1
2
3
4
5
6
7
def mymap(aFunc, aSeq):
result = []
for x in aSeq: result.append(aFunc(x))
return result
map(square, [1, 2, 3]) # [1, 4, 9]
mymap(square, [1, 2, 3]) # [1, 4, 9]

接下來就來看看 map() 有哪些進階用法。

More about map()

map() 其實可以接受 N-argument function for N sequence。也就是說,它的 pass-in function 可以一次接受 N 組參數(N 根據 pass-in function 而定),比如說這樣的程式碼:

1
2
3
4
pow(3,5)
pow(2,10)
pow(3,11)
pow(4,12)

可以用一行 map() 來簡化:

1
list(map(pow,[2, 3, 4], [10, 11, 12])) # [1024, 177147, 16777216]

在這個例子裡,pow() 就一次接受 [2,3,4][10,11,12] 兩組參數,可以達成一樣的結果。

而如果 pass-in function 是 None,會回傳同樣的 sequence。如果 sequence 參數有兩組以上,則會回傳相對應的 list of tuples。

1
2
3
4
5
m = [1,2,3]
n = [1,4,9]
map(None, m) # [1,2,3]
map(None, m, n) # [(1, 1), (2, 4), (3, 9)]

map() 大概就玩到這邊,有什麼新發現之後再補吧。

參考文章:http://www.bogotobogo.com/python/python_fncs_map_filter_reduce.php