2010-06-19 33 views
7

我想計算域內偶數的和。我有兩個解決方案,但我不確定每個解決方案的優缺點。哪個是最佳解決方案?這兩個解決方案之間有什麼區別 - lambda或loop - Python

import sys 
domain = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
Cal1 = sum(filter(lambda n : n % 2 == 0, domain)) 
Cal2 = sum([n for n in domain if n % 2 == 0]) 
sys.stdout.write("Cal1 = {0}\n".format(Cal1)) 
sys.stdout.write("Cal2 = {0}\n".format(Cal2)) 

回答

12

第二真的應該只是一個發電機,而不是一個列表理解(因爲你實際上並不需要創建一個列表,能夠總結髮電機的輸出):

Cal2 = sum(n for n in domain if n % 2 == 0) 

這是完成此任務的現在首選(「pythonic」)方法。

  • 使用列表理解(一個包括[],你原來Cal2)是不利的,因爲它實際上構造了一個列表對象返回,其中有開銷。

  • 使用filter(您Cal1)相當於一個生成器(NO- []版本),但需要多一點打字,不看了不少,以及只使用一個生成器表達式(我上面貼的代碼)。

+0

感謝名單親愛的^ _^ 那麼,有什麼用拉姆達的?我怎麼可以在我的程序中使用? 例子PLZ .. – kilobaik 2010-06-19 18:30:12

+0

'lambda'用於當你需要傳遞一個短功能的東西,而這個功能只是輸入的基本轉換。例如,Python庫中的一些'sort'函數允許您將函數傳遞給它們以比較兩個項目,如果您想以非標準方式對列表進行排序 - 那麼您可以使用類似'lambda x,y:<這裏x和y之間的比較>'。另外,不客氣。 :) – Amber 2010-06-19 18:31:52

+0

@Karamela:例如:'reduce(lambda acc,(i,x):acc^i^x,enumerate(arr),0)'http://stackoverflow.com/questions/2605766/how-to-找到一個重複的元素在一個陣列混洗連續整數 – jfs 2010-06-19 18:36:01

2

你做的第二種方法就是所謂的列表理解。在引入語言之前,列表解析可用於實現以前使用filtermap的事物。請參閱this previous question以獲得關於列表解析與地圖的討論,該地圖與您所要求的相似。

由於Amber寫道,推薦的Pythonic方法是使用發生器。隨着列表comprehsions你的整個過濾列表建立,然後求和。隨着發電機的發展,它會在沒有完整列表的情況下進行求和。當您使用超過10個項目時,這會產生更大的差異。

2

+1對其他很好的答案。

獎勵:發電機表達式是更快...

$ python -m timeit -s 'L = xrange(10)' 'sum(filter(lambda n: n % 2 == 0, L))' 
100000 loops, best of 3: 3.59 usec per loop 

$ python -m timeit -s 'L = xrange(10)' 'sum(n for n in L if n % 2 == 0)' 
100000 loops, best of 3: 2.82 usec per loop 

Docs re timeit

+0

aha .. thanx,現在我明白了:D – kilobaik 2010-06-19 18:43:43

6

這裏是一個老十歲上下的Mac筆記本電腦的各種版本的速度:

$ py26 -mtimeit -s'domain = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]' 'sum(filter(lambda n : n % 2 == 0, domain))' 
100000 loops, best of 3: 4.41 usec per loop 
$ py26 -mtimeit -s'domain = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]' 'sum([n for n in domain if n % 2 == 0])' 
100000 loops, best of 3: 2.69 usec per loop 
$ py26 -mtimeit -s'domain = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]' 'sum(n for n in domain if n % 2 == 0)' 
100000 loops, best of 3: 2.86 usec per loop 

需要注意的是,雖然genexp版本無疑更冷靜,在listcomp 稍快(可能不是通過足夠擔心,除非這個代碼是在一個緊密的內部循環,你正在努力優化鼻子;-)。像往常一樣,基於lambda的版本要慢得多,正如其他人提到的那樣 - lambda在Python中是一種「糟糕的關係」:-(。((並不是說def的函數會在這裏執行得更好))

+0

現在嘗試一個域爲1000000數字,看看會發生什麼。生成器具有設置開銷,但使用較少的內存並且複製較少。介於100k和1M之間的元件,發生器版本變得更快。 – 2010-06-20 01:52:03

+0

@Andrew,取決於可用(和可尋址;-) RAM的數量 - 只要所有內容都可以舒適地存儲在可尋址和物理可用RAM中,listcomp就更快。如你所說,有100萬個數字(Q的域乘以100000),與往常一樣的舊macbook:genexp 178毫秒,listcomp 154毫秒 - 你爲什麼不測量而不是考慮?當然,在**一些**點物理可用/可尋址的RAM將耗盡,並且listcomp將嚴重減慢甚至在Genexp仍然有效時失敗 - 但是在任何體面的現代化機器上,需要** WAY **超過百萬#秒。 – 2010-06-20 02:12:22

+0

順便說一句,@Andrew,在說listcomp做了額外的複製時,你完全錯了 - 它只是把計算的項目放在不同的位置,而不是一遍又一遍的重複 - 不復制。 listcomp'和genexp'都是關於'O(N)'(每個固定開銷的淨值,但當然完全攤銷;-),listcomp只有一個小得多的乘數,所以它運行速度大約快10%這兩個實驗中的%和15%) - 「除非代碼處於嚴密的內部循環中否則不足以擔心」,正如我在A中所說的那樣! – 2010-06-20 02:16:04

相關問題