A.ExRange (Aja v0.5.1) View Source

Exclusive ranges are an exact copy of regular ranges (see `Range`), except that they exclude the second parameter.

Why/when would you need exclusive ranges?

The most typical use case would be when using `1..n` for loops based on a parameter `n >= 0`:

``````iex> incorrect = fn n -> for i <- 1..n, do: "id_#{i}" end
iex> incorrect.(3) # works fine in general...
["id_1", "id_2", "id_3"]
iex> incorrect.(0)  # weird bug at edge case!
["id_1", "id_0"]``````

To fix it, you would typically need to match the `n == 0` case and handle it differently, which is adds noise. With exclusive ranges like `0 ~> n`, you get to keep the compact and elegant approach from above, while having a correct algorithm that covers the edge case:

``````iex> correct = fn n -> for i <- 1 ~> n + 1, do: "id_#{i}" end
iex> correct.(3) # works fine
["id_1", "id_2", "id_3"]
iex> correct.(0)  # edge case works fine too
[]``````

Exclusive ranges can be either increasing (`start <= stop`) or decreasing (`start > stop`). The `start` parameter is included (except if `start == stop`), the `stop` parameter is always excluded.

An exclusive range is represented internally as a struct `A.ExRange{start: start, stop: stop}` and can be used as is.

The `A.~>/2` convenience macro makes it possible to have a more compact syntax, similar to `../2`. It is totally optional and needs to be imported:

``````iex> import A
iex> import A, only: [~>: 2]  # more selective``````

Examples:

``````iex> A.ExRange.new(5)
#A<0 ~> 5>
iex> range = 0 ~> 5
#A<0 ~> 5>
iex> start ~> stop = range
iex> {start, stop}
iex> {0, 4}
iex> Enum.to_list(range)
[0, 1, 2, 3, 4]
iex> Enum.count(range)
5
iex> Enum.member?(range, 5)
false
iex> Enum.member?(range, 4)
true
iex> Enum.to_list(3 ~> 0)
[3, 2, 1]``````

Just like `Range`s, 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.

Functions

Checks if two ranges are disjoint.

Creates a new exclusive range. `start` defaults to 0.

Specs

`t() :: %A.ExRange{start: integer(), stop: integer()}`

disjoint?(range1, range2)

View Source

Specs

`disjoint?(t(), t()) :: boolean()`

Checks if two ranges are disjoint.

Examples

``````iex> A.ExRange.disjoint?(1 ~> 6, 6 ~> 9)
true
iex> A.ExRange.disjoint?(6 ~> 1, 6 ~> 9)
true
iex> A.ExRange.disjoint?(1 ~> 6, 5 ~> 9)
false
iex> A.ExRange.disjoint?(1 ~> 6, 2 ~> 7)
false``````

new(start \\ 0, stop)

View Source

Specs

`new(integer(), integer()) :: t()`

Creates a new exclusive range. `start` defaults to 0.

Examples

``````iex> A.ExRange.new(0, 100)
#A<0 ~> 100>
iex> A.ExRange.new(10)
#A<0 ~> 10>``````