Aplex
Aplex

Reputation: 162

Python - faster way to do for loops

I was just wondering if anyone knew a faster / more efficient way to test this.

(It's suppose to write out every solution to the equation)

        for z in range(500):
           for x in range(500):
             for y in range(500):
               if (x * 80) + (z * 65) + (y * 50) == 1950:
                 print("x " + str(x) + " z " + str(z) + " y " + str(y))

Thanks!

Upvotes: 2

Views: 19937

Answers (2)

Eric Duminil
Eric Duminil

Reputation: 54313

We assume that x,y,z must be positive integers. There's an infinity of solutions otherwise.

Calculate y from x and z

Here's a method which should be 500x faster than yours, simply because it doesn't iterate over y :

for z in range(500):
    for x in range(500):
        fifty_y = 1950 - (x * 80) - (z * 65)
        if fifty_y >= 0 and (fifty_y % 50) == 0:
            y = fifty_y // 50
            print("x " + str(x) + " z " + str(z) + " y " + str(y))

By iterating over x, y and z, you're basically shooting in the dark and hoping that it lands on 1950.

But you know that 50 * y = 1950 - x * 80 - z * 65, so you can calculate y directly from x and z.

50 * y should be positive, and if y is to be an integer, it should be divisible by 50.

Restrict x and z

range(500) is far too big for x and z if we want y to be positive.

range(1950 // 65 + 1) should be enough for z.

Knowing z, range((1950 - 65 * z)// 80 + 1) will be enough for x.

As a bonus, we're sure that 50 * y is positive and we can remove one test :

for z in range(1950 // 65 + 1):
    for x in range((1950 - 65 * z) // 80 + 1):
        fifty_y = 1950 - (x * 80) - (z * 65)
        if (fifty_y % 50) == 0:
            y = fifty_y // 50
            print("x " + str(x) + " z " + str(z) + " y " + str(y))

With Wolfram Alpha

By typing the equation in wolfram alpha, we get :

Integer solution: y = 13 n + x, z = -10 n - 2 x + 30, n element Z

That's perfect! For any x, we just need to choose n so that both y and z are positive. There's no need for if anymore. This code iterates 42 times to display 42 solutions :

for x in range(1950 // 80 + 1):
    for n in range(- (x // 13), (30 - 2 * x) // 10 + 1):
        z = -10 * n - 2 * x + 30
        y = 13 * n + x
        print("x " + str(x) + " z " + str(z) + " y " + str(y))

It almost fits in one line :

print [(x, 13 * n + x, 30 - 10 * n - 2 * x) for x in range(25) for n in range(-(x // 13), (30 - 2 * x) // 10 + 1)]

This code is alsost 3 million times faster than your original code :)

Upvotes: 13

Kyrubas
Kyrubas

Reputation: 897

This will make you a generator of list containing your x,y,z values that produce 1950. The advantage of the generator construct is that the values are generated when called for instead of then the object is created.

the_vals = ([x,y,z] for x in range(500) for y in range(500) for z in range(500) if (x * 80) + (z * 65) + (y * 50) == 1950)

Then to print it out you can just do

for x,y,z in the_vals:
    print("x " + str(x) + " z " + str(z) + " y " + str(y))

Upvotes: 3

Related Questions