在 Python 的 __builtin__
模組中有一些函式,不需要 import
也可以使用,有幾個簡單好用的資料處理函式值得介紹:
range(start, stop[, step])
zip([iterable, ...])
enumerate(sequence, start=0)
filter
map
range
、zip
與 enumerate
要瞭解這些資料處理函式如何使用,最好的方式就是從練習開始 …
練習 6:使用 range
、zip
與 enumerate
在 Python 中,如果想使用 for in
語法來迭代 list
,而且希望取得索引資訊,該如何進行呢?例如,如果有個 list = ['Justin', 'caterpillar', 'openhome']
,想要有以下的顯示結果:
0, Justin
1, caterpillar
2, openhome
先給個小提示,程式基本上可以長這樣:
names = ['Justin', 'caterpillar', 'openhome']
for ______ in ______:
print('{0}, {1}'.format(______))
試著想想,如果使用分別使用 range
、zip
與 enumerate
,那麼程式中三個空白處怎麼寫呢?別忘了,查看一下 range
、zip
與 enumerate
的文件,他們都在 __builtin__
模組的文件中。
別忘了,你可以在 Lab 檔案的 solutions 目錄找到解答。
filter
、map
如果你有個 lt = ['Justin', 'caterpillar', 'openhome']
,現在打算過濾出字串長度大於 6 的元素,按照命式式的寫法可能是:
lt = ['Justin', 'caterpillar', 'openhome']
result = []
for ele in lt:
if len(ele) > 6:
result.append(ele)
print(result)
仔細想想,這類過濾某清單而後取得另一清單的流程,你寫過幾次呢?每次其實只有過濾的條件不同,其他流程都是相同的,如果將重複的流程提取出來,封裝為函式如何呢?
def filter_lt(predicate, lt):
result = []
for ele in lt:
if predicate(ele):
result.append(ele)
return result
lt = ['Justin', 'caterpillar', 'openhome']
print(filter_lt(lambda ele: len(ele) > 6, lt))
print(filter_lt(lambda ele: 'i' in ele, lt))
可以看到,將重複的流程提取出來後,你就可以呼叫函式,然後每次給予不同的 lambda
來設定過濾條件。類似地,如果你想將 lt
的元素全部轉為大寫後傳回新的清單,按照命令式的寫法,可能會是:
lt = ['Justin', 'caterpillar', 'openhome']
result = []
for ele in lt:
result.append(ele.upper())
print(result)
同樣地,將清單元素轉換為另一組清單,也是你寫過無數次的操作,何不將其中重複的流程抽取出來呢?
def map_lt(mapper, lt):
result = []
for ele in lt:
result.append(mapper(ele))
return result
lt = ['Justin', 'caterpillar', 'openhome']
print(map_lt(lambda ele: ele.upper(), lt))
print(map_lt(lambda ele: len(ele), lt))
可以看到,將重複的流程提取出來後,你就可以呼叫函式,然後每次給予不同的 lambda
來設定對應轉換的方式。實際上,Python 就內建有 filter
、map
函式可以直接取用。例如:
t = ['Justin', 'caterpillar', 'openhome']
print(list(filter(lambda ele: len(ele) > 6, lt)))
print(list(filter(lambda ele: 'i' in ele, lt)))
print(list(map(lambda ele: ele.upper(), lt)))
print(list(map(lambda ele: len(ele), lt)))
要注意的是,在 Python 3.x 中,map
、filter
傳回的實例並不是 list
,而是個產生器(Generator),這是為了效率,因為實際上還沒有真正進行過濾或轉換的動作,只有在真正需要結果元素時,才會執行相對應的操作,這稱之為惰性求值(Lazy evaluation),想想看,如果你想依某條件過濾清單後取得結果的前三個元素,惰性求值下,實際上就只要過濾出三個元素就可以了,若原始清單很長,這種惰性的特性對效率會很有助益。
因為 map
、filter
實際傳回產生器,為了要能取得最後的清單並顯示,最後是使用了 list
函式,從產生器逐一取得結果元素,然後組成一個 list
傳回。