# Ranges¶

Ranges are like intervals in mathematics. They have a start and end. Every value between the enpoints is included in the range. Integer ranges (`intrange`) will be used for all examples. Built in range types are listed in Available range types.

A simple range:

```>>> span = intrange(1, 5)
>>> span.lower
1
>>> span.upper
5
```

By default all ranges include all elements from and including lower up to but not including upper. This means that the last element included in the discrete `intrange` is 4.

```>>> intrange(1, 5).last
4
```

Non discrete ranges, such as `floatrange`, do not have the property last `last`.

Discrete ranges are always normalized, while normal ranges are not.

```>>> intrange(1, 5, upper_inc=True)
intrange(1, 6)
>>> floatrange(1.0, 5.0, upper_inc=True)
floatrange(1.0, 5.0, upper_inc=True)
```

The `__repr__` for ranges follows the same format as used by PostgreSQL’s ranges. `[` and `]` means that the boundaries are included in the range and `(` and `)` means that they are not.

Ranges support set operations such as `union`, `difference` and `intersection`.

```>>> intrange(1, 5).union(intrange(5, 10))
intrange(1, 10)
>>> intrange(1, 10).difference(intrange(5, 15))
intrange(1, 5)
>>> intrange(1, 10).intersection(intrange(5, 15))
intrange(5, 10)
```

Unions and differences that would result in two sets will result in a `ValueError`. To perform such operations Range sets must be used.

```>>> intrange(1, 5).union(intrange(10, 15))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Ranges must be either adjacent or overlapping
```

Note

This behavior is for consistency with PostgreSQL.

## Available range types¶

The following range types are built in:

## Range sets¶

Range sets are sets of intervals, where each element must be represented by one and only one range. Range sets are the solution to the problem when an operation will result in two separate ranges.

```>>> intrangeset([intrange(1, 5), intrange(10, 15)])
intrangeset([intrange(1, 5), intrange(10, 15)])
```

Like ranges, range sets support `union`, `difference` and `intersection`. Contrary to Python’s built in sets these operations do not modify the range set in place. Instead it returns a new set. Unchanged ranges are reused to conserve memory since ranges are immutable.

Range sets are however mutable structures. To modify an existing set in place the `add` and `remove` methods are used.

```>>> span = intrangeset([intrange(1, 5)])