#374 · Iterators and generators · Advanced · 135 XP · about 30 min
range(0, 10 ** 18, 7) holds about 142 quadrillion numbers, yet it takes almost no memory and answers questions about them instantly. Build MyRange, a class that does the same, without using the built-in range.
MyRange(stop), MyRange(start, stop) and MyRange(start, stop, step) mean the same as with range: the numbers start, start + step, start + 2 * step and so on, stopping before stop. When step is negative, the numbers go down and stop before going down to stop. start is 0 and step is 1 when they are not given. A step of 0 raises ValueError.iter(r) (and so a for loop, or list(r)) gives the numbers in order. A MyRange can be looped over any number of times, and each loop starts from the beginning.len(r) returns how many numbers there are.r[i] returns the number at index i; negative indexes count from the end. An index outside the range raises IndexError.x in r is True when the whole number x is one of the numbers.len, r[i] and in must answer at once, even for ranges of 10^18 numbers.
list(MyRange(5)) # [0, 1, 2, 3, 4] list(MyRange(2, 12, 3)) # [2, 5, 8, 11] r = MyRange(10, 0, -3) list(r) # [10, 7, 4, 1] len(r) # 4 r[-1] # 1 4 in r, 5 in r # (True, False)
x in x in r are integersstart and stop can be anywhere between -10^18 and 10^18The Python in your browser is 32-bit: len() there cannot go past 2,147,483,647, even for the built-in range. The tests ask len() only of smaller ranges; indexing and in are tested on the giant ones, so work out the size with your own arithmetic there instead of calling len(self).
First solves only, ranked by stars and then time.