2012-01-05 83 views
5

警告,這是一個有點遞歸;)定時功能

我回答了這個問題:Python:How can i get all the elements in a list before the longest element?

我提交那裏有另一種答案,應該是更快的(筆者認爲後,所以沒有我) 。我嘗試瞭解不同的解決方案,但應該更慢的解決方案實際上更快。這讓我覺得我的代碼有問題。或者是?

import string 
import random 
import time 

def solution1(lst): 
    return lst[:lst.index(max(lst, key=len))] 

def solution2(lst): 
    idx, maxLenStr = max(enumerate(lst), key=lambda x:len(x[1])) 
    return lst[:idx] 

# Create a 100000 elements long list that contains 
# random data and random element length 
lst = [] 
for i in range(100000): 
    s = "".join([random.choice(string.letters+string.digits) for x in range(1, random.randint(1,50))]) 
    lst.append(s) 

# Time the first solution 
start = time.time() 
solution1(lst) 
print 'Time for solution1', (time.time() - start) 

# Time the second solution 
start = time.time() 
solution2(lst) 
print 'Time for solution2', (time.time() - start) 

更新

之前有人提到爲什麼我把這個作爲一個新的問題。這個問題更多的是關於我學習如何測量執行時間...

+1

這兩個函數不返回同一類型的對象 – joaquin 2012-01-05 12:06:11

+0

衛生署的!當然:)謝謝! – 2012-01-05 12:07:39

+0

修正了它。但是,這甚至讓我的代碼更快......而且我仍然認爲solution2應該更快.. – 2012-01-05 12:09:24

回答

3

拉姆達耗資在第二溶液可貴更快一個另一個例子。

我異型兩種代碼和配置文件數據,它看起來,第一個解決方案是更快

由於wiki會說的函數調用是昂貴的,在第二方案中,Lambda和Len函數調用是使其運行速度較慢

請注意,我的名單下調到長度爲1000元

>>> cProfile.run('solution1(lst)') 
     5 function calls in 0.000 CPU seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.000 0.000 <pyshell#305>:1(solution1) 
     1 0.000 0.000 0.000 0.000 <string>:1(<module>) 
     1 0.000 0.000 0.000 0.000 {max} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
     1 0.000 0.000 0.000 0.000 {method 'index' of 'list' objects} 


>>> cProfile.run('solution2(lst)') 
     2004 function calls in 0.012 CPU seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.012 0.012 <pyshell#306>:1(solution2) 
    1000 0.006 0.000 0.009 0.000 <pyshell#306>:2(<lambda>) 
     1 0.000 0.000 0.012 0.012 <string>:1(<module>) 
    1000 0.003 0.000 0.003 0.000 {len} 
     1 0.003 0.003 0.012 0.012 {max} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
+0

我想接受所有答案,因爲它們很有價值。但我只能選擇一個,我認爲這是最好的解釋。謝謝 :) – 2012-01-05 12:27:40

2

時間看起來沒問題。

solution1可以更快,因爲它不使用lambdas,所以它不需要在循環中調用Python代碼。它會重複列表兩次,但這不是什麼大問題。

+0

@joaquin是的,你說得對。我正在刪除我的評論以避免混淆。謝謝你讓我知道。 – jcollado 2012-01-05 12:53:19

3

看來第一個版本比第二個版本少了很多。

順便說一句,這可能是慣用的,簡單的代碼是如何經常也用Python

>>> dis.dis(solution1) 
    2   0 LOAD_FAST    0 (lst) 
       3 LOAD_FAST    0 (lst) 
       6 LOAD_ATTR    0 (index) 
       9 LOAD_GLOBAL    1 (max) 
      12 LOAD_FAST    0 (lst) 
      15 LOAD_CONST    1 ('key') 
      18 LOAD_GLOBAL    2 (len) 
      21 CALL_FUNCTION   257 
      24 CALL_FUNCTION   1 
      27 SLICE+2    
      28 RETURN_VALUE   
>>> dis.dis(solution2) 
    2   0 LOAD_GLOBAL    0 (max) 
       3 LOAD_GLOBAL    1 (enumerate) 
       6 LOAD_FAST    0 (lst) 
       9 CALL_FUNCTION   1 
      12 LOAD_CONST    1 ('key') 
      15 LOAD_CONST    2 (<code object <lambda> at 000000000422BEB8, file "<input>", line 2>) 
      18 MAKE_FUNCTION   0 
      21 CALL_FUNCTION   257 
      24 UNPACK_SEQUENCE   2 
      27 STORE_FAST    1 (idx) 
      30 STORE_FAST    2 (maxLenStr) 

    3   33 LOAD_FAST    0 (lst) 
      36 LOAD_FAST    1 (idx) 
      39 SLICE+2    
      40 RETURN_VALUE 
+0

沒關係。對於任何合理的大數據,被調用的函數需要更多的時間。 – zch 2012-01-05 12:24:24

+0

@zch對不起,我沒有明白,你能解釋你的評論嗎? – joaquin 2012-01-05 12:33:13

+0

每個測試只能調用一次所有說明。函數'max'的運行時間與輸入列表的長度成正比。因此,對於足夠大的列表(在這種情況下不是很大),運行'max'將花費比執行其他指令更多的時間。 – zch 2012-01-05 12:45:56