2011年8月31日 星期三

[python]reduce的觀念

從python裡,我學到一組對我來說很重要的觀念。
一個是 map,另一個是 reduce。
這兩個對我寫程式的影響很大。
而 reduce 對我來說,真的是比較難理解。
而我最近才比較了解一點點。
在網路上,大多文章談到 reduce,多是舉官方文件的例子:

def sum_num(x,y):
    return x + y
a = [1,2,3,4,5]
b = reduce(sum_num, a)

或者是更簡潔地:

a = [1,2,3,4,5]
b = reduce(lambda x,y : x + y, a)

在我想要做更複雜的事情的時候,腦筋就轉不過來。
難道,只能做數值運算嗎?

讓我們來看一下 reduce 的函數定義,其為

reduce(func, iter, [initial_value])

套用於上面的例子,你可以認為
b = reduce(sum_num, a)
等同於
b = reduce(sum_num, a, 0)

然後,把 reduce(sum_num, a, 0) 想像成如下的函數:

def reduce(func_handler, value_list, init_value):
    b = init_value
    for value in value_list:
        b = func_handler(b, value)
    return b

所以,想像一下,要使用 reduce,要準備三個東西,
(1)一個函數,有兩個傳入值,一個輸出值,這些值,都是屬於同一集合的元素。
(2)一個list,是要被處理的元素。
(3)起始值。

例如,我有一組資料長相如下:
a = [(1,a,3),(2,b,6),(3,c,9),(4,d,12)]
我想要把計算每個tuple的第一個總和、每個tuple的第二個字元要連接、每個tuple的第三個乘積。
也就是要得到
(1+2+3+4,’abcd’,3*6*9*12)
我要準備函數,為了好理解,特別寫成下面的樣子
def sum_special(x, y):
    i0 = x[0]+y[0]
    i1 = x[1]+y[1] #字串相加
    i2 = x[2]*y[2]
    return (i0, i1, i2)
要處理的 list 就是 a,
起始值就是 (0, ‘’, 0) 了。

reduce 這樣用就對了。

當你的程式看到很多次的

a = func(a, b)
a = func(a, c)
a = func(a, d)

或是

b = init_value
for value in value_list:
    b = func_handler(b, value)

那就轉用 reduce 吧。

1 則留言:

  1. 你給的sample我想好久才知道怎麼解
    應該是這樣
    >>>reduce(lambda v1,v2: [v1[0]+v2[0], str(v1[1]) + str(v2[1]), v1[2]*v2[2]], [(1,'a',3),(2,'b',6),(3,'c',9),(4,'d',12)], [0, '', 1])
    [10, 'abcd', 1944]

    回覆刪除