如何更有效地编写此解决方案?

时间:2013-03-16 08:50:50

标签: python performance python-2.7

import random

a = [int(1000*random.random()) for i in xrange(10)]
b = [int(1000*random.random()) for i in xrange(10)]
c = [int(1000*random.random()) for i in xrange(10)]
d = dict()
for i in xrange(len(a)):
    for j in xrange(len(b)):
        for k in xrange(len(c)):
            if (i+j+k == 10):
                d[(i,j,k)] = a[i]+b[j]+c[k]

print max(d.values())

该代码在a,b,c中找到最佳元素三元组,以便最大化a[i]+b[j]+b[k]i+j+k=10成立

4 个答案:

答案 0 :(得分:4)

首先,您可以更改循环的边界并摆脱最里面的循环:

import random
a = [int(1000*random.random()) for i in xrange(10)]
b = [int(1000*random.random()) for i in xrange(10)]
c = [int(1000*random.random()) for i in xrange(10)]
d = dict()
for i in xrange(10):
    for j in xrange(10 - i):
        k = 10 - i - j
        if k < len(c):
            d[(i,j,k)] = a[i]+b[j]+c[k]

print max(d.values())

这将运行时间提高了~4.5倍:

In [2]: %timeit original()
10000 loops, best of 3: 166 us per loop

In [3]: %timeit new()
10000 loops, best of 3: 36.1 us per loop

答案 1 :(得分:3)

由于您实际上并未使用dict的密钥,因此您可以更快地构建并迭代list。但是,既然你实际上并没有对值进行任何操作,除了调用max之外,你可以随时跟踪最大值,而不是构建和迭代任何东西

修改NPE的解决方案:

import random
a = [int(1000*random.random()) for i in xrange(10)]
b = [int(1000*random.random()) for i in xrange(10)]
c = [int(1000*random.random()) for i in xrange(10)]
maxval = 0
for i in xrange(10):
    for j in xrange(10 - i):
        k = 10 - i - j
        if k < len(c):
            val = a[i]+b[j]+c[k]
            if val > maxval:
                maxval = val
print maxval

这使得它比CPython中的版本快得多,但它在PyPy中产生了巨大的差异。

                 OP    HYRY   NPE    AB
CPython 2.7.2    161.  98.8   46.9   38.0
PyPy 1.9.0       11.8  7.28   7.39   2.46

毋庸置疑,首先使用PyPy而不是CPython比任何人建议的任何微优化都要大得多。


对于一个真正的问题,你有1000000个值而不是10个,这是解决它的一种可怕的方法。

首先,只需将值保存为int32值的数组而不是Python list,就可以减少内存使用量(因此缩短分页时间,缓存命中率等)秒。一旦你完成了,你也可以把它放在1000000x3 numpy.array中。然后你只需要构建一个i + j + k == 1000000的掩码数组,应用掩码,并在其中找到最大值。这将你所有的循环移动到C,我猜它会快10-30倍。远远超过你将用Python进行微优化。

但你可能想要走向另一个方向。你需要列表存在吗?如果你有一系列的数据被生成/读取/懒惰,有没有办法做到这一点,而无需将整个内容读入内存?看起来你只需要完整的两个列表 - 如果你能控制第三个到达的顺序,那么只需要一个。事实上,如果你可以控制第三个的顺序,你只需要生成/读取它的前10%。

答案 2 :(得分:1)

将函数包装在函数中将增加变量查找速度,您不需要第三个循环:

import random
def f(random=random.random):
    a = [int(1000*random()) for i in xrange(10)]
    b = [int(1000*random()) for i in xrange(10)]
    c = [int(1000*random()) for i in xrange(10)]
    d = {}
    for i in xrange(len(a)):
        for j in xrange(len(b)-i):
            k = 10 - i - j
            if 0 <= k < 10:
                d[i,j,k] = a[i]+b[j]+c[k]
    return max(d.values())
f()

如果您只想要最大值,则不需要dict。

答案 3 :(得分:0)

我认为缓存random.random查找可以显着提高性能。

import random

def f():
    rand = random.random
    a = [int(1000*rand()) for _ in xrange(10)]
    b = [int(1000*rand()) for _ in xrange(10)]
    c = [int(1000*rand()) for _ in xrange(10)]
    d = dict()
    for i in xrange(10):
        for j in xrange(10 - i):
            k = 10 - i - j
            if 0 <= k < 10:
                d[(i,j,k)] = a[i]+b[j]+c[k]

    print max(d.values())

f()