Calculating square numbers within a range (python)

I want to be able to execute the following code:

for i in Squares(5, 50): print(i) 

Now this is very easy to implement with a loop, however I want to use an iterator.

So, I defined the following class:

 import math class Squares(object): def __init__(self, start, stop): self.start = start self.stop = stop def __iter__(self): return self def __next__(self): start = self.start stop = self.stop squareroot = math.sqrt(start) if self.start > self.stop: raise StopIteration if squareroot == math.ceil(squareroot): start += 1 

But for now, this returns None infinite number of times. This means that none of them should be, because StopIteration is executed, even if it should not. I think my condition if squareroot == math.ceil(squareroot): correct, because I tested it separately, but I cannot figure out what to change to get the result I want. Any help is appreciated.

EDIT: for code, for example:

 for i in Squares(4, 16): print(i) 

I expect the output to be as follows:

 4 9 16 
+5
source share
5 answers

Try creating a generator function:

 from math import sqrt, ceil def Squares(start, stop): for i in range(start, stop+1): sqrti = sqrt(i) if sqrti == ceil(sqrti): yield i 

And then run it:

 for i in Squares(4, 20): print i, 

which will tell:

 4 9 16 

EDIT: edited according to the square definition, not the previous square force (sorry: P). Added +1 to range to match the example question OP.

+3
source

I think you wanted to continue to increase the start until you reach the next square, and not increase it only if it is a square:

 def __next__(self): self.start += 1 squareroot = math.sqrt(self.start) while squareroot != math.ceil(squareroot): if self.start > self.stop: raise StopIteration self.start += 1 squareroot = math.sqrt(self.start) 
+2
source

You can simplify arithmetic using

 (n + 1)**2 == n**2 + (2*n + 1) 

Here's how to do it using the generator function:

 import math def squares(lo, hi): root = int(math.ceil(lo ** 0.5)) num = root ** 2 delta = 2 * root + 1 while num <= hi: yield num num += delta delta += 2 print list(squares(4, 16)) print list(squares(5, 50)) print list(squares(20, 90)) 

Output

 [4, 9, 16] [9, 16, 25, 36, 49] [25, 36, 49, 64, 81] 

Here is the equivalent iterator class. I gave it the __repr__ method, so it looks good if you print an instance of this class.

 import math class Squares(object): def __init__(self, start, stop): self.start = start self.stop = stop root = int(math.ceil(start ** 0.5)) self.num = root ** 2 self.delta = 2 * root + 1 def __repr__(self): return 'Squares(%d, %d)' % (self.start, self.stop) def __iter__(self): return self def next(self): num = self.num if num > self.stop: raise StopIteration self.num += self.delta self.delta += 2 return num sq = Squares(4, 16) print sq for i in sq: print i print list(Squares(5, 50)) print list(Squares(20, 90)) 

Output

 Squares(4, 16) 4 9 16 [9, 16, 25, 36, 49] [25, 36, 49, 64, 81] 

For Python 3, replace the next method name with __next__ .

The usual Python range convention should stop before you reach the upper limit. To make this code consistent with this convention, in changing the squares() generator

 while num <= hi: 

to

 while num < hi: 

and in class squares() change

 if num > self.stop: 

to

 if num >= self.stop: 
+1
source

The easiest way:

 import math class Squares(object): def __init__(self, start, stop): self._squares = range(start, stop + 1) def __iter__(self): return self._squares.__iter__() def __next__(self): if math.sqrt(self._squares.next()) == math.ceil(math.sqrt(self._squares.next())): return math.sqrt(self._squares.next()) if __name__ == '__main__': for i in Squares(5, 50): print i 
0
source
 from math import ceil, sqrt start,stop = 4,16 gen_sqr = ( i for i in range( start, stop +1) if sqrt(i) == ceil( sqrt(i)) ) 

Now you have your own square generator:

 gen_sqr.next() #4 gen_sqr.next() #9 list(gen_sqr) #[16] 
0
source

All Articles