# View Source Range (Elixir v1.17.0-dev)

Ranges represent a sequence of zero, one or many, ascending or descending integers with a common difference called step.

The most common form of creating and matching on ranges is
via the `first..last`

and `first..last//step`

notations, auto-imported from `Kernel`

:

```
iex> 1 in 1..10
true
iex> 5 in 1..10
true
iex> 10 in 1..10
true
```

Ranges are always inclusive in Elixir. When a step is defined, integers will only belong to the range if they match the step:

```
iex> 5 in 1..10//2
true
iex> 4 in 1..10//2
false
```

When defining a range without a step, the step will be
defined based on the first and last position of the
range, If `last >= first`

, it will be an increasing range
with a step of 1. Otherwise, it is a decreasing range.
Note, however, implicit decreasing ranges are deprecated.
Therefore, if you need a decreasing range from `3`

to `1`

,
prefer to write `3..1//-1`

instead.

`../0`

can also be used as a shortcut to create the range `0..-1//1`

,
also known as the full-slice range:

```
iex> ..
0..-1//1
```

## Use cases

Ranges typically have two uses in Elixir: as a collection or to represent a slice of another data structure.

### Ranges as collections

Ranges in Elixir are enumerables and therefore can be used
with the `Enum`

module:

```
iex> Enum.to_list(1..3)
[1, 2, 3]
iex> Enum.to_list(3..1//-1)
[3, 2, 1]
iex> Enum.to_list(1..5//2)
[1, 3, 5]
```

Ranges may also have a single element:

```
iex> Enum.to_list(1..1)
[1]
iex> Enum.to_list(1..1//2)
[1]
```

Or even no elements at all:

```
iex> Enum.to_list(10..0//1)
[]
iex> Enum.to_list(0..10//-1)
[]
```

The full-slice range, returned by `../0`

, is an empty collection:

```
iex> Enum.to_list(..)
[]
```

### Ranges as slices

Ranges are also frequently used to slice collections. You can slice strings or any enumerable:

```
iex> String.slice("elixir", 1..4)
"lixi"
iex> Enum.slice([0, 1, 2, 3, 4, 5], 1..4)
[1, 2, 3, 4]
```

In those cases, the first and last values of the range are mapped to positions in the collections.

If a negative number is given, it maps to a position from the back:

```
iex> String.slice("elixir", 1..-2//1)
"lixi"
iex> Enum.slice([0, 1, 2, 3, 4, 5], 1..-2//1)
[1, 2, 3, 4]
```

The range `0..-1//1`

, returned by `../0`

, returns the
collection as is, which is why it is called the full-slice
range:

```
iex> String.slice("elixir", ..)
"elixir"
iex> Enum.slice([0, 1, 2, 3, 4, 5], ..)
[0, 1, 2, 3, 4, 5]
```

## Definition

An increasing range `first..last//step`

is a range from `first`

to `last`

increasing by `step`

where `step`

must be a positive
integer and all values `v`

must be `first <= v and v <= last`

.
Therefore, a range `10..0//1`

is an empty range because there
is no value `v`

that is `10 <= v and v <= 0`

.

Similarly, a decreasing range `first..last//step`

is a range
from `first`

to `last`

decreasing by `step`

where `step`

must
be a negative integer and values `v`

must be `first >= v and v >= last`

.
Therefore, a range `0..10//-1`

is an empty range because there
is no value `v`

that is `0 >= v and v >= 10`

.

## Representation

Internally, ranges are represented as structs:

```
iex> range = 1..9//2
1..9//2
iex> first..last//step = range
iex> first
1
iex> last
9
iex> step
2
iex> range.step
2
```

You can access the range fields (`first`

, `last`

, and `step`

)
directly but you should not modify nor create ranges by hand.
Instead use the proper operators or `new/2`

and `new/3`

.

Ranges implement the `Enumerable`

protocol with memory
efficient versions of all `Enumerable`

callbacks:

```
iex> range = 1..10
1..10
iex> Enum.reduce(range, 0, fn i, acc -> i * i + acc end)
385
iex> Enum.count(range)
10
iex> Enum.member?(range, 11)
false
iex> Enum.member?(range, 8)
true
```

Such function calls are efficient memory-wise no matter the
size of the range. The implementation of the `Enumerable`

protocol uses logic based solely on the endpoints and does
not materialize the whole list of integers.

# Summary

## Functions

Checks if two ranges are disjoint.

Creates a new range.

Creates a new range with `step`

.

Shifts a range by the given number of steps.

Returns the size of `range`

.

Splits a range in two.

Converts a range to a list.

# Types

@type limit() :: integer()

@type step() :: pos_integer() | neg_integer()

@type t(first, last) :: %Range{first: first, last: last, step: step()}

# Functions

Checks if two ranges are disjoint.

## Examples

```
iex> Range.disjoint?(1..5, 6..9)
true
iex> Range.disjoint?(5..1//-1, 6..9)
true
iex> Range.disjoint?(1..5, 5..9)
false
iex> Range.disjoint?(1..5, 2..7)
false
```

Steps are also considered when computing the ranges to be disjoint:

```
iex> Range.disjoint?(1..10//2, 2..10//2)
true
# First element in common is 29
iex> Range.disjoint?(1..100//14, 8..100//21)
false
iex> Range.disjoint?(57..-1//-14, 8..100//21)
false
iex> Range.disjoint?(1..100//14, 50..8//-21)
false
iex> Range.disjoint?(1..28//14, 8..28//21)
true
# First element in common is 14
iex> Range.disjoint?(2..28//3, 9..28//5)
false
iex> Range.disjoint?(26..2//-3, 29..9//-5)
false
# Starting from the back without alignment
iex> Range.disjoint?(27..11//-3, 30..0//-7)
true
```

Creates a new range.

If `first`

is less than `last`

, the range will be increasing from
`first`

to `last`

. If `first`

is equal to `last`

, the range will contain
one element, which is the number itself.

If `first`

is greater than `last`

, the range will be decreasing from `first`

to `last`

, albeit this behavior is deprecated. Therefore, it is advised to
explicitly list the step with `new/3`

.

## Examples

```
iex> Range.new(-100, 100)
-100..100
```

Creates a new range with `step`

.

## Examples

```
iex> Range.new(-100, 100, 2)
-100..100//2
```

Shifts a range by the given number of steps.

## Examples

```
iex> Range.shift(0..10, 1)
1..11
iex> Range.shift(0..10, 2)
2..12
iex> Range.shift(0..10//2, 2)
4..14//2
iex> Range.shift(10..0//-2, 2)
6..-4//-2
```

@spec size(t()) :: non_neg_integer()

Returns the size of `range`

.

## Examples

```
iex> Range.size(1..10)
10
iex> Range.size(1..10//2)
5
iex> Range.size(1..10//3)
4
iex> Range.size(1..10//-1)
0
iex> Range.size(10..1//-1)
10
iex> Range.size(10..1//-2)
5
iex> Range.size(10..1//-3)
4
iex> Range.size(10..1//1)
0
```

Splits a range in two.

It returns a tuple of two elements.

If `split`

is less than the number of elements in the range, the first
element in the range will have `split`

entries and the second will have
all remaining entries.

If `split`

is more than the number of elements in the range, the second
range in the tuple will emit zero elements.

## Examples

Increasing ranges:

```
iex> Range.split(1..5, 2)
{1..2, 3..5}
iex> Range.split(1..5//2, 2)
{1..3//2, 5..5//2}
iex> Range.split(1..5//2, 0)
{1..-1//2, 1..5//2}
iex> Range.split(1..5//2, 10)
{1..5//2, 7..5//2}
```

Decreasing ranges can also be split:

```
iex> Range.split(5..1//-1, 2)
{5..4//-1, 3..1//-1}
iex> Range.split(5..1//-2, 2)
{5..3//-2, 1..1//-2}
iex> Range.split(5..1//-2, 0)
{5..7//-2, 5..1//-2}
iex> Range.split(5..1//-2, 10)
{5..1//-2, -1..1//-2}
```

Empty ranges preserve their property but still return empty ranges:

```
iex> Range.split(2..5//-1, 2)
{2..3//-1, 4..5//-1}
iex> Range.split(2..5//-1, 10)
{2..3//-1, 4..5//-1}
iex> Range.split(5..2//1, 2)
{5..4//1, 3..2//1}
iex> Range.split(5..2//1, 10)
{5..4//1, 3..2//1}
```

If the number to split is negative, it splits from the back:

```
iex> Range.split(1..5, -2)
{1..3, 4..5}
iex> Range.split(5..1//-1, -2)
{5..3//-1, 2..1//-1}
```

If it is negative and greater than the elements in the range, the first element of the tuple will be an empty range:

```
iex> Range.split(1..5, -10)
{1..0//1, 1..5}
iex> Range.split(5..1//-1, -10)
{5..6//-1, 5..1//-1}
```

## Properties

When a range is split, the following properties are observed.
Given `split(input)`

returns `{left, right}`

, we have:

```
assert input.first == left.first
assert input.last == right.last
assert input.step == left.step
assert input.step == right.step
assert Range.size(input) == Range.size(left) + Range.size(right)
```

Converts a range to a list.

## Examples

```
iex> Range.to_list(0..5)
[0, 1, 2, 3, 4, 5]
iex> Range.to_list(-3..0)
[-3, -2, -1, 0]
```