简体   繁体   中英

How can I write this solution more efficiently?

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())

that code finds the best triples of elements in a,b,c such that maximizes a[i]+b[j]+b[k] and i+j+k=10 holds

To start with, you could change the boundaries of your loops and get rid of the innermost loop:

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())

This improves the runtime by a factor of ~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

Since you're not actually using the dict 's keys, you could build and iterate a list more quickly. But, since you're not actually doing anything with the values, either, except to call max , you can just keep track of the max value as you go along, and not build and iterate anything .

Modifying NPE's solution:

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

This makes it significantly faster than his version in CPython, but it makes a huge difference in 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

Needless to say, using PyPy instead of CPython in the first place is a much bigger win than any of the micro-optimizations anyone's suggested.


For a real problem, where you have 1000000 values instead of 10, this is a terrible way to solve it.

For one thing, you can cut your memory usage (and therefore your paging time, cache hits, etc.) way down just by saving the values as arrays of int32 values instead of Python list s. And once you've done that, you might as well put it in a 1000000x3 numpy.array . Then you just need to build a mask array of i+j+k==1000000, apply the mask, and find the max value in it. That moves all your loops into C, and I'm guessing it'll be 10-30x faster. Much more than you're going to get out of micro-optimizations with Python.

But you might want to go the other direction. Do you need the lists to exist at all? If you've got a sequence of data being generated/read/whatever lazily, is there a way to do this without reading the whole thing into memory? It seems like you only need two of the lists in full—and only one if you can control the order the third arrives. In fact, if you can control the order of the third one, you only need to generate/read the first 10% of it.

wrap your code in a function will increase variable lookup speed, an you don't need the third loop:

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()

and if you only want the max value, you don't need the dict.

I think caching random.random lookup can improve the performance dramatically.

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM