2012-01-05 42 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