程式扎記: Python Tutorial 第三堂(2)資料處理函式

標籤

2014年8月4日 星期一

Python Tutorial 第三堂(2)資料處理函式

來源自 這裡 
Preface 
在 Python 的 __builtin__ 模組 中有一些函式,不需要 import 也可以使用,有幾個簡單好用的資料處理函式值得介紹: 
range(start, stop[, step])
zip([iterable, ...])
enumerate(sequence, start=0)
reduce(function, iterable[, initializer])

range、zip 與 enumerate 
要瞭解這些資料處理函式如何使用,最好的方式就是從練習開始 … 

練習 6:使用 range、zip 與 enumerate 
在 Python 中,如果想使用 for in 語法來迭代 list,而且希望取得索引資訊,該如何進行呢?例如,如果有個 list = ['Justin', 'caterpillar', 'openhome'],想要有以下的顯示結果: 
0, Justin
1, caterpillar
2, openhome

先給個小提示,程式基本上可以長這樣: 
  1. names = ['Justin''caterpillar''openhome']  
  2. for ______ in ______:  
  3.     print '{0}, {1}'.format(______)  
試著想想,如果使用分別使用 range、zip 與 enumerate,那麼程式中三個空白處怎麼寫呢?別忘了,查看一下 range、zip 與 enumerate 的文件,他們都在 __builtin__ 模組 的文件中。 
 

reduce 
__builtin__ 模組 中的 reduce,有時在別的語言中會被稱為 foldLeft,它其實代表了一種高度抽象化後的流程重用,只要是打算從清單中求值的需求,基本上都可以使用它。 

舉例來說,如果你想要知道 [1, 2, 3, 4, 5] 的加總,雖然可以直接撰寫迴圈來求值,不過,也可以撰寫為 reduce(lambda sum, elem: sum + elem, [1, 2, 3, 4, 5], 0) 來求值,試試在 Python 互動環境中鍵入,結果會是 15。初學者會有點難懂 reduce 的原理,可以藉由這段動畫來理解,你也就會知道,為什麼它又在別的語言中,被稱為 foldLeft: 
 

如果 reduce 接受的 lambda 部份,改為一個具體名稱的 add 函式,那麼就可以寫為 為 reduce(add, [1, 2, 3, 4, 5], 0) ,配合上圖,reduce 的運作就像是折紙,從 0 開始,每折一次就與藍色數字進行一次 add,折完後的結果就是加總值。 

練習 7:使用 reduce 
使用 reduce 與 for 包含式,將以下的範例進行重構,目標是清除所有顯式的迴圈流程: 
  1. # coding=UTF-8  
  2. def ascending(a, b): return a - b  
  3. def descending(a, b): return -ascending(a, b)  
  4. # selection sort  
  5. def sorted(xs, compare = ascending):  
  6.     return [] if not xs else __select(xs, compare)  
  7.   
  8. def __select(xs, compare):  
  9.     selected = xs[0]  
  10.     for elem in xs[1:]:  
  11.         if compare(elem, selected) < 0:  
  12.             selected = elem  
  13.   
  14.     remain = []  
  15.     selected_list = []  
  16.     for elem in xs:  
  17.         if elem != selected:  
  18.             remain.append(elem)  
  19.         else:  
  20.             selected_list.append(elem)  
  21.   
  22.     return xs if not remain else selected_list + __select(remain, compare)  
  23.   
  24. print sorted([21365])  
  25. print sorted([21365], descending)  
下面是一種解法: 
  1. # coding=UTF-8  
  2. def ascending(a, b): return a - b  
  3. def descending(a, b): return -ascending(a, b)  
  4. # selection sort  
  5. def _sorted(xs, compare = ascending):  
  6.     return [] if not xs else __select(xs, compare)  
  7.   
  8. def _sep(slt, elm, remain, selected_list):  
  9.     if elm != slt:  
  10.         remain.append(elm)  
  11.     else:  
  12.         selected_list.append(elm)  
  13.     return slt      
  14.   
  15. def __select(xs, compare):  
  16.     selected = xs[0]  
  17.     reduce(lambda slt, elm: slt if compare(elm, selected) > 0 else elm, xs[1:], selected)  
  18.   
  19.     remain = []  
  20.     selected_list = []              
  21.     reduce(_sep, xs, selected)      
  22.     return xs if not remain else selected_list + __select(remain, compare)  
  23.   
  24. print _sorted([213652])  
  25. print _sorted([213652], descending)  


關於函數式程式設計 
想要知道 reduce 的原理,可以看看 List 處理模式 中的說明。 實際上,reduce 與 for 包含式的概念源自函數式程式設計Functional programming),嗯?好像很高深,其實如果你能完成練習 7,你已經做了一次函數式程式設計了。 

不過,何時該使用函數式的元素,取決於可讀與風格問題,在 Python 中確實是有那麼一些函數式程式設計的元素,for 包含式在 Python 中應用的很多,因為可以增加可讀性,然而像 reduce 這種元素,由於可讀性並不好,因而並不太鼓勵去用它,用更具體的函式名稱來封裝 reduce 會更好,以上面的加總來說,可以寫個 sum 函式來表達意圖。實際上,在 Python 3 中,reduce 不再位於 __builtin__ 模組,而被移至 funtools 模組了。 

無論如何,藉由這個練習,瞭解到 Python 可進行多重典範設計,只要你願意的話,函數式是可以的設計之一;接下來的內容,是要介紹 Python 中對永續化(Persistence)的基本支援,順便來看看幾種永續設計方式 - Python Tutorial 第三堂(3)永續化機制 

Supplement 
python內置函數 map/reduce/filter

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!