range

https://docs.python.org/3/library/stdtypes.html#ranges

INTRODUCTION

Sequences of integers are very common and that is why Python has special tools to handle them.

+--------------------------+---------------------------+
| Operation                | Meaning                   |
+--------------------------+---------------------------+
| range(start, stop, step) | list (Py2)                |
| range(start, stop)       | step=1                    |
| range(stop)              | start=0, step=1           |
| for x in range(n): pass  | iteration                 |
| xrange(i, j, k)          | generator (Py2)           |
| for x in xrange(n): pass | iteration (Py2)           |
+--------------------------+---------------------------+
| R = range(i, j, k)       | generator (Py3)           |
| len(R)                   | length                    |
| L = list(R)              | make a list               |
| R.start                  | start (Py3.3+)            |
| R.stop                   | stop (Py3.3+)             |
| R.step                   | step (Py3.3+)             |
| for x in R: pass         | iteration                 |
| x in R                   | containing                |
| x not in R               | containing                |
| R.index(x)               | first occurrence          |
| R.count(x)               | number of occurrences     |
| max(R), min(R)           | the largest|smallest item |
| R[i]                     | get item at index         |
| R[i:j]                   | slice of R (new range)    |
| R[i:j:k]                 | slice of R (new range)    |
| R1 == R2, R1 != R2       | compare as sequences      |
| del R                    | remove the name R         |
+--------------------------+---------------------------+

INDEXING AND SLICING


R[i]       # i from 0 to len(R)-1
R[-n] == R[len(R)-n]
R[-1]     # the last item

R[:j] == R[0:j]   # j not included
R[i:] == R[i:len(R)]   # from i to the end
R[::k] == R[0:len(R):k]   # step k
R[::-k] == R[len(R)-1:-1:-k]   # decreasing
R2 = R1[:]   # copy

# A 'slice' object can represent a slicing operation.
# slice(stop)
# slice(start, stop[, step])
# S.indices(len) returns (start, stop, stride)

assert R[i:j:k] == R[slice(i, j, k)]
assert R[i:j] == R[slice(i, j, None)]   # or slice(i, j)
assert R[i:] == R[slice(i, None, None)]
assert R[:j] == R[slice(None, j, None)]   # or slice(j)
assert R[::-1] == R[slice(None, None, -1)]

s = slice(0, 5)
assert s.indices(10) == (0, 5, 1)   # 10 is an assumed length of a sequence
assert s.indices(4) == (0, 4, 1)
assert isinstance(s, slice)   # 'slice' is a class

PYTHON 2

In Python 2, 'range' is a builtin function that retuns a list.

'xrange' returns an object that generates the numbers in the range on demand.


range(i, j) returns [i, i+1, i+2, ..., j-1] for i < j (step=1).
range(i, j, -1) returns [i, i-1, i-2, ..., j+1] for i > j.
The end point is omitted!
When 'step' is given, it specifies the increment (or decrement).

range(i, j, k) returns [i, i+k, i+2*k, ..., last], where usually
i < last < j for k > 0, 
i > last > j for k < 0.

PYTHON 3

The 'range' type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in 'for' loops.

The advantage of the 'range' type over a regular 'list' or 'tuple' is that a 'range' object will always take the same (small) amount of memory, no matter the size of the range it represents. It only stores the 'start', 'stop' and 'step' values, calculating individual items and subranges as needed.


list(range(1, 6))         # [1, 2, 3, 4, 5]
list(range(4))            # [0, 1, 2, 3], start=0
list(range(1, 9, 2))      # [1, 3, 5, 7], step=2
list(range(5, 2, -1))     # [5, 4, 3]
list(range(1, 0))         # [], empty range, start >= stop
list(range(0))            # [], empty range, start == stop

assert range(0, 3, 2) == range(0, 4, 2)   # note that 'stop' differs
r1 = range(5)   # list(r1) == [0, 1, 2, 3, 4]
r2 = range(4,-1,-1)   # list(r2) == [4, 3, 2, 1, 0]
assert r1 != r2   # ordering is important!

import sys

r1 = range(1, 10, 2)
list(r1)   # [1, 3, 5, 7, 9]
r2 = r1[0:10:2]   # range(1, 11, 4)
list(r2)   # [1, 5, 9]
r3 = range(pow(10, 10))   # range(0, 10000000000)

sys.getsizeof(r1)   # 48 bytes
sys.getsizeof(r2)   # 48 bytes
sys.getsizeof(r3)   # 48 bytes

EXERCISES

(1) Make a range with even numbers from 0 to 2020.

(2) Make a range with odd numbers from 1 to 2021.

(3) Make a range with numbers that can be divided by 3, from 0 to 2022.