当前位置:编程学习 > 网站相关 >>

命令式至函數式隨記(五)

來點輕鬆的好了!要把一組list中的資料全部加1怎麼寫?
def addOne(list):
    result = []
    for ele in list:
        result.append(ele + 1)
    return result

改成函數式呢?
def addOne(list):
    return [] if list == [] else [list[0] + 1] + addOne(list[1:])

那要把一組list中的資料全部乘3呢?
def multiplyThree(list):
    return [] if list == [] else [list[0] * 1] + multiplyThree(list[1:])

那要把一組list中的資料全部OOXX呢?乾脆寫個通用的map:
def map(func, list):
    return [] if list == [] else [func(list[0])] + map(func, list[1:])

那麼要把一組list中的資料全部加1就可以:
map(lambda ele: ele + 1, list)

把一組list中的資料全部乘3就可以:
map(lambda ele: ele * 3, list)

要把一組list中的資料OOXX就可以:
map(lambda ele: OOXX(ele), list)

類似地,要將list中大於3的元素過濾出來怎麼寫?
def greatThanThree(list):
    result = []
    for ele in list:
        if ele > 3:
            result.append(ele)
    return result

改成函數式呢?
def greatThanThree(list):
    return [] if list == [] else \
        ([list[0]] + greatThanThree(list[1:]) if list[0] > 3 else greatThanThree(list[1:]))

如果想將list中小於3的元素過濾出來呢?你會寫出類似結構的東西,所以直接寫個filter吧!
def filter(func, list):
    return [] if list == [] else \
        ([list[0]] + filter(func, list[1:]) if func(list[0]) else filter(func, list[1:]))

那麼要將list中小於3的元素過濾出來就是:
filter(lambda ele: ele > 3, list)

到這邊可以看到,map、filter與先前文章談的fold,都是很常運用的動作,因為程式經常就是在對一組資料作這些動作。不過你有沒有發現, map、filter的結構與fold很像?實際上map、filter都可以用fold來實現。例如直接用Python的functool中 reduce(也就是foldLeft的實現)來寫個map:
def map(func, list):
    return reduce(lambda lt, elem: lt + [func(elem)], list, [])

也可以用reduce來實現filter:
def filter(func, list):
    return reduce(lambda lt, elem: lt + [elem] if func(elem) else lt, list, [])

你要直接用reduce把一組list中的資料全部加1也可以,只不過會寫成reduce(lambda lt, elem: lt + [elem + 1], list, []),要直接用reduce將list中小於3的元素過濾出來也可以,只不過會寫成reduce(lambda lt, elem: lt + [elem] if elem > 3 else lt, list, []),這時還不如分別寫為map(lambda ele: ele + 1, list)與filter(lambda ele: ele > 3, list)清楚,當然要更清楚還可以寫成addOne(list)、greaterThanThree(list),這是可讀性的問題。使用通用 reduce、map、filter不要過火就是這樣,你願意的話,可以都用map、filter、reduce重頭寫到尾,但是略為封裝一下可以讓語義 清晰的話,不妨為之。要加總[1, 2, 3],你是用Python內建的sum寫sum([1, 2, 3])好呢?還是reduce(lambda s, e: s + e, [1, 2, 3], 0)好呢?還是reduce(int.__add__, [1, 2, 3], 0)好呢?

Python中的functools除了有reduce之外,也有map與filter,不過傳回值與這邊自行實作的不太一樣,Python的map與 filter不是直接傳回list,而分別是map與filter物件,簡單來說,它們實作了 產 生器,如果要取得list,可以使用list函式。例如list(map(int.__add__, [1, 2, 3]))或list(filter(lambda ele: ele > 3, [1, 2, 3, 4, 5]))。

實際上有些語言提供有list comprehension語法,可用比較簡單的語法來作到map、filter。例如Python中要將所有元素加1,可以[ele + 1 for ele in list],要將大於3的元素過濾出來,可以[ele for ele in list if ele > 3],熟悉Python的應該常用這個語法。

基本上map、filter作得到的,list comprehension都作得到,但list comprehension作得到的,map、filter可能會囉嗦點。例如一個情況是巢狀時:
[(i, j) for i in [1, 2, 3] for j in [4, 5, 6]]

這會產生[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)],如果用這邊自行定義的map,加上functools中的reduce來寫,至少得寫成:
reduce(list.__add__, map(lambda i: map(lambda j: (i, j),  [4, 5, 6]), [1, 2, 3]))

不過list comprehension也不只是為了簡潔一些而設立的語法,在某些語言中,會讓它的樣子更像數學表達式,例如數學中1到100的正整數中由2倍數組成 的數列可表達為 {2 * x | x ∈ {1, 2..100}},若用Haskell的list comprehension來寫,會是[2 * x | x <- [1, 2..100]],跟原本的數學定義真的是蠻像的。

补充:综合编程 , 其他综合 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,