Reputation: 1571
I want to calaculate pythagorean triplets(code below) and I want to calculate infinitly how do I do it without using the three for loops? Could I use a for loop in some way? thanks.
import math
def main():
for x in range (10000, 1000):
for y in range (10000, 1000):
for z in range(10000, 1000):
if x*x == y*y + z*z:
print y, z, x
print '-'*50
if __name__ == '__main__':
main()
Upvotes: 3
Views: 6965
Reputation: 156
How about use itertools.product instead?
# range is [10000, 1000)
for x, y, z in itertools.product(range(10000, 1000, -1), repeat=3):
if x * x == y * y + z * z:
print(y, z, x)
with a litter bit optimize:
for x, y, z in itertools.product(range(10000, 1000, -1), repeat=3):
if y >= x or z >= x or x >= (y + z) or z < y:
continue
if x * x == y * y + z * z:
print(y, z, x)
EDIT:Here I just give a way to use product
instead of multiple for loop. And you can find more efficient method in above posts.
Upvotes: 0
Reputation: 204768
Not the most efficient (Python will build an array with a billion tuples), but this is a single loop:
for x, y, z in [(x, y, z) for x in range(10000, 11000) for y in range(10000, 11000) for z in range(10000, 11000)]:
if x*x == y*y + z*z:
print y, z, x
print '-'*50
Or, as suggested by Christian Witts,
for x, y, z in ((x, y, z) for x in xrange(10000, 11000) for y in xrange(10000, 11000) for z in xrange(10000, 11000)):
if x*x == y*y + z*z:
print y, z, x
print '-'*50
(assuming Python >= 2.4) uses generators instead of building a billion-tuple array.
Either way, you shouldn't code like this... Your initial code with nested loops is clearer.
Upvotes: 1
Reputation:
At least three loops are needed for infinity. To make something flexible takes a ton of loops. This example is a solution to Project Euler Problem 9 and more.
#!/usr/bin/env python
def fcount(start=1):
n = float(start)
while True:
yield n
n += 1
def find_triples():
for c in fcount():
for b in fcount():
if b > c:
break
for a in fcount():
if a > b:
break
if a ** 2 + b ** 2 == c ** 2:
yield (a, b, c)
def triples_by_sum(targetsum):
for a, b, c in find_triples():
if a + b + c == targetsum:
yield a, b, c
if c > targetsum:
break
if __name__ == '__main__':
# Finds multiple triples
for a, b, c in triples_by_sum(252):
print a, b, c
# Finds single triples
a, b, c = triples_by_sum(1000).next()
print a, b, c
# Goes forever
for a, b, c in find_triples():
print a, b, c
Upvotes: 0
Reputation: 5652
Here's an efficient version, using iterators, that generates all such triples, in order. The trick here is to iterate up through the sets of (x,y) pairs that sum to N, for all N.
import math import itertools def all_int_pairs(): "generate all pairs of positive integers" for n in itertools.count(1): for x in xrange(1,n/2+1): yield x,n-x for x,y in all_int_pairs(): z = math.sqrt(x**2 + y**2) if int(z) == z: print x, y, int(z) print '-'*50
Upvotes: 2
Reputation: 79103
You would only need two loops - just check to see if math.sqrt(x*x+y*y)
is an integer. If it is, you've discovered a pythagorean triple.
I'm new to Python, so I don't know what range(10000, 1000)
does - where does it start and stop? I ask because you can halve your runtime by having the range for y
start at x
instead of fixing it, due to the fact that addition is commutative.
edit: This answer is what I was getting at, and what I would have written if I knew more Python.
Upvotes: 4
Reputation: 3835
Using the same algorithm (see the other answers for better approaches), you can use itertools.count to get a loop that runs forever.
import itertools
for x in itertools.count(1):
for y in xrange(1, x):
for z in xrange(1, y):
if x*x == y*y + z*z:
print x, y, z
Upvotes: 1
Reputation: 166162
If you want to count to infinity ..
Create a generator function that counts from zero and never stops, and use the for loop on it
def inf():
i = 0
while True:
yield i
i = i + 1
for i in inf():
print i # or do whatever you want!
I don't know if there's already such a builtin function
Upvotes: 0
Reputation: 38189
This is the same as Can Berk Guder's answer, but done as a generator, just for fun. It's not really useful with the nested loops here, but it can often be a cleaner solution. Your function produces results; you worry later about how many to retrieve.
import math
def triplets(limit):
for x in range(1, limit):
for y in range(x, limit):
z = math.sqrt(x**2 + y**2)
if int(z) == z:
yield x, y, int(z)
for x, y, z in triplets(10):
print x, y, z
print "-" * 50
Upvotes: 1
Reputation: 36174
Using xrange instead of range
should use less memory, especially if you want to try large ranges.
Upvotes: 2
Reputation: 113310
Generally, you can't. Three variables, three loops.
But this is a special case, as nobody pointed out. You can solve this problem with two loops.
Also, there's no point in checking y, z and z, y.
Oh, and range(10000, 1000) = []
.
import math
for x in range(1, 1000):
for y in range(x, 1000):
z = math.sqrt(x**2 + y**2)
if int(z) == z:
print x, y, int(z)
print '-'*50
Upvotes: 8
Reputation: 993173
You can arrange your code in a single main loop like this:
MIN = 10000
MAX = 10010
a = [MIN, MIN, MIN]
while True:
print a
for i in range(len(a)):
a[i] = a[i] + 1
if a[i] < MAX:
break
a[i] = MIN
i += 1
else:
break
Instead of the print a
, you can do your Pythagorean triplet test there. This will work for an arbitrary number of dimensions.
If you really want to do this infinitely, you will have to use a different iteration technique such as diagonalization.
Upvotes: 4
Reputation: 124652
Besides what has already been posted, people would expect three loops for three collections. Anything else may get very confusing and provide no added benefit.
Upvotes: 0