# A.Vector (Aja v0.4.3) View Source

A Clojure-like persistent vector with efficient appends and random access.

Persistent vectors are an efficient alternative to lists. Many operations for `A.Vector` run in effective constant time (length, random access, appends...), unlike linked lists for which most operations run in linear time. Functions that need to go through the whole collection like `map/2` or `foldl/3` are as often fast as their list equivalents, or sometimes even slightly faster.

Vectors also use less memory than lists for "big" collections (see the Memory usage section).

Erlang's `:array` module offer similar functionalities. However `A.Vector`:

Note: most of the design is inspired by this series of blog posts, but a branching factor of `16 = 2 ^ 4` has been picked instead of `32 = 2 ^ 5`. This choice was made following performance benchmarking that showed better overall performance for this particular implementation.

## Examples

``````iex> vector = A.Vector.new(1..10)
#A<vec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])>
iex> A.Vector.append(vector, :foo)
#A<vec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, :foo])>
iex> vector
4
iex> A.Vector.replace_at(vector, -1, :bar)
#A<vec([1, 2, 3, 4, 5, 6, 7, 8, 9, :bar])>
iex> 3 in vector
true``````

## Access behaviour

`A.Vector` implements the `Access` behaviour.

``````iex> vector = A.Vector.new(1..10)
iex> vector
4
iex> put_in(vector, :foo)
#A<vec([1, 2, 3, 4, 5, :foo, 7, 8, 9, 10])>
iex> {9, updated} = pop_in(vector); updated
#A<vec([1, 2, 3, 4, 5, 6, 7, 8, 10])>``````

## Convenience `vec/1` macro

The `A.Vector` module can be used without any macro. The `A.vec/1` macro does however provide some syntactic sugar to make it more convenient to work with vectors of known size, namely:

• construct new vectors of known size faster, by generating the AST at compile time
• pattern match on elements for vectors of known size

Examples:

``````iex> import A
iex> vec([1, 2, 3])
#A<vec([1, 2, 3])>
iex> vec([1, 2, var, _, _, _]) = A.Vector.new(1..6); var
3``````

## Pattern-matching and opaque type

An `A.Vector` is represented internally using the `%A.Vector{}` struct. This struct can be used whenever there's a need to pattern match on something being an `A.Vector`:

``````iex> match?(%A.Vector{}, A.Vector.new())
true``````

Note, however, than `A.Vector` is an opaque type: its struct internal fields must not be accessed directly.

As discussed in the previous section, `vec/1` makes it possible to pattern match on size and elements as well as checking the type.

## Memory usage

Vectors have a small overhead over lists for smaller collections, but are using far less memory for bigger collections:

``````iex> memory_for = fn n -> [Enum.to_list(1..n), A.Vector.new(1..n)] |> Enum.map(&:erts_debug.size/1) end
iex> memory_for.(1)
[2, 28]
iex> memory_for.(10)
[20, 28]
iex> memory_for.(100)
[200, 150]
iex> memory_for.(10_000)
[20000, 11370]``````

If you need to work with vectors containing mostly the same value, `A.Vector.duplicate/2` should be highly efficient both in time and memory, since it minimizes the number of actual copies and reuses the same nested structures under the hood:

``````iex> A.Vector.duplicate(0, 1_000) |> :erts_debug.size()
133
iex> A.Vector.duplicate(0, 1_000) |> :erts_debug.flat_size()  # when shared over processes / ETS
1170``````

## Efficiency guide

If you are using vectors and not lists, chances are that you care about performance. Here are a couple notes about how to use vectors in an optimal way. Most functions from this module are highly efficient, those that are not will indicate it in their documentation.

But remember the golden rule: in case of doubt, always benchmark.

### Avoid prepending

Appending is very efficient, but prepending is highly inefficient since the whole array needs to be reconstructed.

DON'T

``A.Vector.prepend(vector, :foo)``

DO

``````[:foo | list]  # use lists
A.Vector.append(vector, :foo)``````

### Avoid deletions

This implementation of persistent vectors has many advantages, but it does not support efficient deletion, with the exception of the last element that can be popped very efficiently (`A.Vector.pop_last/1`, `A.Vector.delete_last/1`).

Deleting close to the end of the vector is still fairly fast, but deleting near the beginning needs to reconstruct most of the vector.

Deletion functionality is provided through functions like `A.Vector.pop_at/3` and `A.Vector.delete_at/2` for the sake of completion, but please note that they are inefficient and their usage is discouraged.

If you need to be able to pop arbitrary indexes, chances are you should consider an alternative data structure. Another possibility could be to use sparse arrays, defining `nil` as a deleted value (but then the indexing and size won't reflect this).

DON'T

``````A.Vector.pop_at(vector, 3)
A.Vector.delete_at(vector, 3)
pop_in(vector)``````

DO

``````A.Vector.pop_last(vector)
A.Vector.delete_last(vector)
A.Vector.delete_at(vector, -3)  # close to the end
A.Vector.replace_at(vector, 3, nil)``````

### Successive appends

If you just need to append all elements of an enumerable, it is more efficient to use `A.Vector.append_many/2` than successive calls to `A.Vector.append/2`:

DON'T

``````Enum.reduce(enumerable, vector, fn val, acc -> A.Vector.append(acc, val) end)
Enum.into(enumerable, vector)``````

DO

``A.Vector.append_many(vector, enumerable)``

### Prefer `A.Vector` to `Enum` for vectors

Many functions provided in this module are very efficient and should be used over `Enum` functions whenever possible, even if `A.Vector` implements the `Enumerable` and `Collectable` protocols for convienience:

DON'T

``````Enum.sum(vector)
Enum.to_list(vector)
Enum.reduce(vector, [], fun)
Enum.into(enumerable, %A.Vector.new())
Enum.into(enumerable, vector)``````

DO

``````A.Vector.sum(vector)
A.Vector.to_list(vector)
A.Vector.foldl(vector, [], fun)
A.Vector.new(enumerable)
A.Vector.append_many(vector, enumerable)``````

`for` comprehensions are actually using `Enumerable` as well, so the same advice holds:

DON'T

``````for value <- vector do
do_stuff()
end``````

DO

``````for value <- A.Vector.to_list(vector) do
do_stuff()
end``````

### Exceptions: `Enum` optimized functions

`Enum.member?/2` is implemented in an efficient way, so `in/2` is optimal:

DO

``33 in vector``

`Enum.slice/2` and `Enum.slice/3` are optimized and their use is encouraged, other "slicing" functions like `Enum.take/2` or `Enum.drop/2` however are inefficient:

DON'T

``````Enum.take(vector, 10)
Enum.drop(vector, 25)``````

DO

``````Enum.slice(vector, 0, 10)
Enum.slice(vector, 0..10)
Enum.slice(vector, 25..-1)``````

### Slicing optimization

Slicing any subset on the left on the vector using methods from `A.Vector` is extremely efficient as the vector internals can be reused:

DO

``````A.Vector.take(vector, 10)  # take a positive amount
A.Vector.drop(vector, -20)  # drop a negative amount
A.Vector.slice(vector, 0, 10)  # slicing from 0
A.Vector.slice(vector, 0..-5)  # slicing from 0``````

### `A.Vector` and `Enum` APIs

Not all `Enum` functions have been mirrored in `A.Vector`, but you can try either to:

Also, it is worth noting that several `A.Vector` functions return vectors, not lists like their `Enum` counterpart:

``````iex> vector = A.Vector.new(1..10)
iex> A.Vector.map(vector, & (&1 * 7))
#A<vec([7, 14, 21, 28, 35, 42, 49, 56, 63, 70])>
iex> A.Vector.reverse(vector)
#A<vec([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])>``````

• If you need to work with vectors containing mostly the same value, use `A.Vector.duplicate/2` (more details in the Memory usage section).

• If you work with functions returning vectors of known size, you can use the `A.vec/1` macro to defer the generation of the AST for the internal structure to compile time instead of runtime.

``````A.Vector.new([a, 1, 2, 3, 4])  # structure created at runtime
vec([a, 1, 2, 3, 4])  # structure AST defined at compile time``````

# Link to this section Summary

## Functions

Returns `true` if all elements in `enumerable` are truthy.

Returns `true` if `fun.(element)` is truthy for all elements in `enumerable`.

Returns `true` if at least one element in `enumerable` is truthy.

Returns `true` if `fun.(element)` is truthy for at least one element in `enumerable`.

Appends a `value` at the end of a `vector`.

Appends all values from an `enumerable` at the end of a `vector`.

Finds the element at the given `index` (zero-based).

Finds the element at the given `index` (zero-based).

(Inefficient) Returns a copy of `vector` without the value at the specified `index`.

(Inefficient) Returns a copy of `vector` without the value at the specified `index`.

Removes the last value from the `vector` and returns the updated vector.

Removes the last value from the `vector` and returns the updated vector.

Drops the amount of elements from the `vector`.

Duplicates the given element `n` times in a vector.

Invokes the given `fun` for each element in the `vector`.

Finds the element at the given `index` (zero-based), and returns it in a ok-entry. If the `index` does not exist, returns `:error`.

Filters the `vector`, i.e. return a new vector containing only elements for which `fun` returns a truthy (neither `false` nor `nil`) value.

Returns the first element in the `vector` or `default` if `vector` is empty.

Folds (reduces) the given `vector` from the left with the function `fun`. Requires an accumulator `acc`.

Folds (reduces) the given `vector` from the right with the function `fun`. Requires an accumulator `acc`.

Gets the value from key and updates it, all in one pass.

Intersperses `separator` between each element of the `vector`.

Joins the given `vector` into a string using `joiner` as a separator.

Returns the last element in the `vector` or `default` if `vector` is empty.

Returns a new vector where each element is the result of invoking `fun` on each corresponding element of `vector`.

Maps and intersperses the `vector` in one pass.

Maps and joins the given `vector` into a string using `joiner` as a separator.

Returns the maximal element in the `vector` according to Erlang's term ordering.

Returns the minimal element in the `vector` according to Erlang's term ordering.

Returns a new empty vector.

Creates a vector from an `enumerable`.

Creates a vector from an `enumerable` via the given `transform` function.

(Inefficient) Returns and removes the value at the specified `index` in the `vector`.

(Inefficient) Returns and removes the value at the specified `index` in the `vector`.

Removes the last value from the `vector` and returns both the value and the updated vector.

Removes the last value from the `vector` and returns both the value and the updated vector.

(Inefficient) Prepends `value` at the beginning of the `vector`.

Returns the product of all elements in the `vector`.

Filters the `vector`, i.e. return a new vector containing only elements for which `fun` returns a falsy (either `false` or `nil`) value.

Populates a vector of size `n` by calling `generator_fun` repeatedly.

Returns a copy of `vector` with a replaced `value` at the specified `index`.

Returns a copy of `vector` with a replaced `value` at the specified `index`.

Returns the `vector` in reverse order.

Returns the number of elements in `vector`.

Returns a subset of the given `vector` by `index_range`.

Returns a subset of the given `vector`, from `start_index` (zero-based) with `amount number` of elements if available.

Sorts the `vector` in the same way as `Enum.sort/1`.

Sorts the `vector` in the same way as `Enum.sort/2`.

Sorts the `vector` in the same way as `Enum.sort_by/3`.

Returns the sum of all elements in the `vector`.

Takes an `amount` of elements from the beginning or the end of the `vector`.

Converts the `vector` to a list.

Returns a copy of the vector without any duplicated element.

Returns a copy of the vector without elements for which the function `fun` returned duplicate elements.

Returns a copy of `vector` with an updated value at the specified `index`.

Returns a copy of `vector` with an updated value at the specified `index`.

# index()

View Source

## Specs

`index() :: non_neg_integer()`

# t()

View Source

## Specs

`t() :: t(value())`

# t(value)

View Source (opaque)

## Specs

`t(value)`

# value()

View Source

## Specs

`value() :: term()`

# all?(vector)

View Source

## Specs

`all?(t(val)) :: boolean() when val: value()`

Returns `true` if all elements in `enumerable` are truthy.

Runs in linear time, but stops evaluating when finds the first falsy value.

Iterates over the `enumerable`, and when it finds a falsy value (`false` or `nil`), `false` is returned. In all other cases `true` is returned.

## Examples

``````iex> A.Vector.new([true, true, false]) |> A.Vector.all?()
false
iex> A.Vector.new([true, [], %{}, 5]) |> A.Vector.all?()
true
iex> A.Vector.new() |> A.Vector.all?()
true``````

# all?(vector, fun)

View Source

## Specs

`all?(t(val), (val -> as_boolean(term()))) :: boolean() when val: value()`

Returns `true` if `fun.(element)` is truthy for all elements in `enumerable`.

Runs in linear time, but stops evaluating when finds the first falsy value.

Iterates over the `enumerable` and invokes `fun` on each element. When an invocation of `fun` returns a falsy value (`false` or `nil`) iteration stops immediately and `false` is returned. In all other cases `true` is returned.

## Examples

``````iex> vector = A.Vector.new(1..10)
iex> A.Vector.all?(vector, fn i -> rem(i, 13) != 0 end)
true
iex> A.Vector.all?(vector, fn i -> rem(i, 7) != 0 end)
false
iex> A.Vector.new() |> A.Vector.all?(fn i -> rem(i, 7) != 0 end)
true``````

# any?(vector)

View Source

## Specs

`any?(t(val)) :: boolean() when val: value()`

Returns `true` if at least one element in `enumerable` is truthy.

Runs in linear time, but stops evaluating when finds the first truthy value.

Iterates over the `enumerable`, and when it finds a truthy value (neither `false` nor `nil`), `true` is returned. In all other cases `false` is returned.

## Examples

``````iex> A.Vector.new([false, false, true]) |> A.Vector.any?()
true
iex> A.Vector.new([false, nil]) |> A.Vector.any?()
false
iex> A.Vector.new() |> A.Vector.any?()
false``````

# any?(vector, fun)

View Source

## Specs

`any?(t(val), (val -> as_boolean(term()))) :: boolean() when val: value()`

Returns `true` if `fun.(element)` is truthy for at least one element in `enumerable`.

Runs in linear time, but stops evaluating when finds the first truthy value.

Iterates over the `enumerable` and invokes `fun` on each element. When an invocation of `fun` returns a truthy value (neither `false` nor `nil`) iteration stops immediately and `true` is returned. In all other cases `false` is returned.

## Examples

``````iex> vector = A.Vector.new(1..10)
iex> A.Vector.any?(vector, fn i -> rem(i, 7) == 0 end)
true
iex> A.Vector.any?(vector, fn i -> rem(i, 13) == 0 end)
false
iex> A.Vector.new() |> A.Vector.any?(fn i -> rem(i, 7) == 0 end)
false``````

# append(vector, value)

View Source

## Specs

`append(t(val), val) :: t(val) when val: value()`

Appends a `value` at the end of a `vector`.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new() |> A.Vector.append(:foo)
#A<vec([:foo])>
iex> A.Vector.new(1..5) |> A.Vector.append(:foo)
#A<vec([1, 2, 3, 4, 5, :foo])>``````

# append_many(vector, enumerable)

View Source

## Specs

`append_many(t(val), Enumerable.t()) :: t(val) when val: value()`

Appends all values from an `enumerable` at the end of a `vector`.

Runs in effective linear time in respect with the length of `enumerable`, disregarding the size of the `vector`.

## Examples

``````iex> A.Vector.new(1..5) |> A.Vector.append_many(10..15)
#A<vec([1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15])>
iex> A.Vector.new() |> A.Vector.append_many(10..15)
#A<vec([10, 11, 12, 13, 14, 15])>``````

# at(vector, index, default \\ nil)

View Source

## Specs

`at(t(val), index(), default) :: val | default when val: value(), default: term()`

Finds the element at the given `index` (zero-based).

Returns `default` if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new(1..1_000) |> A.Vector.at(555)
556
iex> A.Vector.new(1..1_000) |> A.Vector.at(1_000)
nil``````

# at!(vector, index)

View Source

Finds the element at the given `index` (zero-based).

Raises an `A.Vector.IndexError` if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new(1..1_000) |> A.Vector.at!(555)
556
iex> A.Vector.new(1..1_000) |> A.Vector.at!(-10)
991
iex> A.Vector.new(1..1_000) |> A.Vector.at!(1_000)
** (A.Vector.IndexError) out of bound index: 1000 not in -1000..999``````

# delete_at(vector, index)

View Source

## Specs

`delete_at(t(val), index()) :: t(val) when val: value()`

(Inefficient) Returns a copy of `vector` without the value at the specified `index`.

Returns the `vector` untouched if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in linear time. Its usage is discouraged, see the Efficiency guide.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> A.Vector.delete_at(vector, 4)
#A<vec([1, 2, 3, 4, 6, 7, 8])>
iex> A.Vector.delete_at(vector, -9)
#A<vec([1, 2, 3, 4, 5, 6, 7, 8])>``````

# delete_at!(vector, index)

View Source

## Specs

`delete_at!(t(val), index()) :: t(val) when val: value()`

(Inefficient) Returns a copy of `vector` without the value at the specified `index`.

Raises an `A.Vector.IndexError` if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in linear time. Its usage is discouraged, see the Efficiency guide.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> A.Vector.delete_at!(vector, 4)
#A<vec([1, 2, 3, 4, 6, 7, 8])>
iex> A.Vector.delete_at!(vector, -9)
** (A.Vector.IndexError) out of bound index: -9 not in -8..7``````

# delete_last(vector)

View Source

## Specs

`delete_last(t(val)) :: t(val) when val: value()`

Removes the last value from the `vector` and returns the updated vector.

Leaves the `vector` untouched if empty.

Runs in effective constant time.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> A.Vector.delete_last(vector)
#A<vec([1, 2, 3, 4, 5, 6, 7])>
iex> A.Vector.delete_last(A.Vector.new())
#A<vec([])>``````

# delete_last!(vector)

View Source

## Specs

`delete_last!(t(val)) :: t(val) when val: value()`

Removes the last value from the `vector` and returns the updated vector.

Raises an `A.Vector.EmptyError` if empty.

Runs in effective constant time.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> A.Vector.delete_last!(vector)
#A<vec([1, 2, 3, 4, 5, 6, 7])>
iex> A.Vector.delete_last!(A.Vector.new())
** (A.Vector.EmptyError) empty vector error``````

# drop(vector, amount)

View Source

## Specs

`drop(t(val), integer()) :: t(val) when val: value()`

Drops the amount of elements from the `vector`.

If a negative `amount` is given, the amount of last values will be dropped.

Time complexity is:

• linear when `amount` is positive, as the vector needs to be reconstructed.
• effective constant time when `amount` is negative, as the vector structure can be shared

## Examples

``````iex> A.Vector.new(0..15) |> A.Vector.drop(10)
#A<vec([10, 11, 12, 13, 14, 15])>
iex> A.Vector.new(0..5) |> A.Vector.drop(0)
#A<vec([0, 1, 2, 3, 4, 5])>
iex> A.Vector.new(0..10) |> A.Vector.drop(-5)
#A<vec([0, 1, 2, 3, 4, 5])>``````

# duplicate(value, n)

View Source

## Specs

`duplicate(val, non_neg_integer()) :: t(val) when val: value()`

Duplicates the given element `n` times in a vector.

`n` is an integer greater than or equal to `0`. If `n` is `0`, an empty list is returned.

Runs in linear time, but is very fast and memory efficient (see Memory usage).

## Examples

``````iex> A.Vector.duplicate(nil, 10)
#A<vec([nil, nil, nil, nil, nil, nil, nil, nil, nil, nil])>
iex> A.Vector.duplicate(:foo, 0)
#A<vec([])>``````

# each(vector, fun)

View Source

## Specs

`each(t(val), (val -> term())) :: :ok when val: value()`

Invokes the given `fun` for each element in the `vector`.

Returns `:ok`.

Runs in linear time.

## Examples

``````A.Vector.new(1..3) |> A.Vector.each(&IO.inspect/1)
1
2
3
:ok``````

# fetch(vector, index)

View Source

## Specs

`fetch(t(val), index()) :: {:ok, val} | :error when val: value()`

Finds the element at the given `index` (zero-based), and returns it in a ok-entry. If the `index` does not exist, returns `:error`.

Supports negative indexing from the end of the `vector`.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new(1..1_000) |> A.Vector.fetch(555)
{:ok, 556}
iex> A.Vector.new(1..1_000) |> A.Vector.fetch(1_000)
:error
iex> A.Vector.new(1..1_000) |> A.Vector.fetch(-1)
{:ok, 1000}``````

# filter(vector, fun)

View Source

## Specs

`filter(t(val), (val -> boolean())) :: t(val) when val: value()`

Filters the `vector`, i.e. return a new vector containing only elements for which `fun` returns a truthy (neither `false` nor `nil`) value.

Runs in linear time.

## Examples

``````iex> vector = A.Vector.new(1..100)
iex> A.Vector.filter(vector, fn i -> rem(i, 13) == 0 end)
#A<vec([13, 26, 39, 52, 65, 78, 91])>``````

# first(vector, default \\ nil)

View Source

## Specs

`first(t(val), default) :: val | default when val: value(), default: term()`

Returns the first element in the `vector` or `default` if `vector` is empty.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new(1..10_000) |> A.Vector.first()
1
iex> A.Vector.new() |> A.Vector.first()
nil``````

# foldl(vector, acc, fun)

View Source

## Specs

`foldl(t(val), acc, (val, acc -> acc)) :: acc when val: value(), acc: term()`

Folds (reduces) the given `vector` from the left with the function `fun`. Requires an accumulator `acc`.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..10) |> A.Vector.foldl(0, &+/2)
55
iex> A.Vector.new(1..10) |> A.Vector.foldl([], & [&1 | &2])
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]``````

# foldr(vector, acc, fun)

View Source

## Specs

`foldr(t(val), acc, (val, acc -> acc)) :: acc when val: value(), acc: term()`

Folds (reduces) the given `vector` from the right with the function `fun`. Requires an accumulator `acc`.

Unlike linked lists, this is as efficient as `foldl/3`. This can typically save a call to `Enum.reverse/1` on the result when building a list.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..10) |> A.Vector.foldr(0, &+/2)
55
iex> A.Vector.new(1..10) |> A.Vector.foldr([], & [&1 | &2])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]``````

# get_and_update(vector, index, fun)

View Source

## Specs

```get_and_update(t(v), index(), (v -> {returned, v} | :pop)) :: {returned, t(v)}
when v: value(), returned: term()```

Gets the value from key and updates it, all in one pass.

See `Access.get_and_update/3` for more details.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> {6, updated} = A.Vector.get_and_update(vector, 5, fn current_value ->
...>   {current_value, current_value && current_value * 100}
...> end); updated
#A<vec([1, 2, 3, 4, 5, 600, 7, 8])>
iex> {nil, updated} = A.Vector.get_and_update(vector, 8, fn current_value ->
...>   {current_value, current_value && current_value * 100}
...> end); updated
#A<vec([1, 2, 3, 4, 5, 6, 7, 8])>
iex> {4, updated} = A.Vector.get_and_update(vector, 3, fn _ -> :pop end); updated
#A<vec([1, 2, 3, 5, 6, 7, 8])>
iex> {nil, updated} = A.Vector.get_and_update(vector, 8, fn _ -> :pop end); updated
#A<vec([1, 2, 3, 4, 5, 6, 7, 8])>``````

# intersperse(vector, separator)

View Source

## Specs

```intersperse(t(val), separator) :: t(val | separator)
when val: value(), separator: value()```

Intersperses `separator` between each element of the `vector`.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..6) |> A.Vector.intersperse(nil)
#A<vec([1, nil, 2, nil, 3, nil, 4, nil, 5, nil, 6])>``````

# join(vector, joiner \\ "")

View Source

## Specs

`join(t(val), String.t()) :: String.t() when val: String.Chars.t()`

Joins the given `vector` into a string using `joiner` as a separator.

If `joiner` is not passed at all, it defaults to an empty string.

All elements in the `vector` must be convertible to a string, otherwise an error is raised.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..6) |> A.Vector.join()
"123456"
iex> A.Vector.new(1..6) |> A.Vector.join(" + ")
"1 + 2 + 3 + 4 + 5 + 6"
iex> A.Vector.new() |> A.Vector.join(" + ")
""``````

# last(vector, default \\ nil)

View Source

## Specs

`last(t(val), default) :: val | default when val: value(), default: term()`

Returns the last element in the `vector` or `default` if `vector` is empty.

Runs in constant time (actual, not effective).

## Examples

``````iex> A.Vector.new(1..10_000) |> A.Vector.last()
10_000
iex> A.Vector.new() |> A.Vector.last()
nil``````

# map(vector, fun)

View Source

## Specs

`map(t(v1), (v1 -> v2)) :: t(v2) when v1: value(), v2: value()`

Returns a new vector where each element is the result of invoking `fun` on each corresponding element of `vector`.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..10) |> A.Vector.map(&(&1 * &1))
#A<vec([1, 4, 9, 16, 25, 36, 49, 64, 81, 100])>``````

# map_intersperse(vector, separator, mapper)

View Source

## Specs

```map_intersperse(t(val), separator, (val -> mapped_val)) ::
t(mapped_val | separator)
when val: value(), separator: value(), mapped_val: value()```

Maps and intersperses the `vector` in one pass.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..6) |> A.Vector.map_intersperse(nil, &(&1 * 10))
#A<vec([10, nil, 20, nil, 30, nil, 40, nil, 50, nil, 60])>``````

# map_join(vector, joiner \\ "", mapper)

View Source

## Specs

```map_join(t(val), String.t(), (val -> String.Chars.t())) :: String.t()
when val: value()```

Maps and joins the given `vector` into a string using `joiner` as a separator.

If `joiner` is not passed at all, it defaults to an empty string.

`mapper` should only return values that are convertible to a string, otherwise an error is raised.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..6) |> A.Vector.map_join(fn x -> x * 10 end)
"102030405060"
iex> A.Vector.new(1..6) |> A.Vector.map_join(" + ", fn x -> x * 10 end)
"10 + 20 + 30 + 40 + 50 + 60"
iex> A.Vector.new() |> A.Vector.map_join(" + ", fn x -> x * 10 end)
""``````

# max(vector)

View Source

## Specs

`max(t(val)) :: val when val: value()`

Returns the maximal element in the `vector` according to Erlang's term ordering.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..10) |> A.Vector.max()
10
iex> A.Vector.new() |> A.Vector.max()
** (A.Vector.EmptyError) empty vector error``````

# min(vector)

View Source

## Specs

`min(t(val)) :: val when val: value()`

Returns the minimal element in the `vector` according to Erlang's term ordering.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..10) |> A.Vector.min()
1
iex> A.Vector.new() |> A.Vector.min()
** (A.Vector.EmptyError) empty vector error``````

# new()

View Source

## Specs

`new() :: t()`

Returns a new empty vector.

## Examples

``````iex> A.Vector.new()
#A<vec([])>``````

# new(vector)

View Source

## Specs

`new(Enumerable.t()) :: t()`

Creates a vector from an `enumerable`.

Runs in linear time.

## Examples

``````iex> A.Vector.new(10..25)
#A<vec([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25])>``````

# new(enumerable, fun)

View Source

## Specs

`new(Enumerable.t(), (v1 -> v2)) :: t(v2) when v1: value(), v2: value()`

Creates a vector from an `enumerable` via the given `transform` function.

## Examples

``````iex> A.Vector.new(1..10, &(&1 * &1))
#A<vec([1, 4, 9, 16, 25, 36, 49, 64, 81, 100])>``````

# pop_at(vector, index, default \\ nil)

View Source

## Specs

```pop_at(t(val), index(), default) :: {val | default, t(val)}
when val: value(), default: term()```

(Inefficient) Returns and removes the value at the specified `index` in the `vector`.

Returns the `vector` untouched if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in linear time. Its usage is discouraged, see the Efficiency guide.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> {5, updated} = A.Vector.pop_at(vector, 4); updated
#A<vec([1, 2, 3, 4, 6, 7, 8])>
iex> {nil, updated} = A.Vector.pop_at(vector, -9); updated
#A<vec([1, 2, 3, 4, 5, 6, 7, 8])>``````

# pop_at!(vector, index)

View Source

## Specs

`pop_at!(t(val), index()) :: {val, t(val)} when val: value()`

(Inefficient) Returns and removes the value at the specified `index` in the `vector`.

Raises an `A.Vector.IndexError` if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in linear time. Its usage is discouraged, see the Efficiency guide.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> {5, updated} = A.Vector.pop_at!(vector, 4); updated
#A<vec([1, 2, 3, 4, 6, 7, 8])>
iex> A.Vector.pop_at!(vector, -9)
** (A.Vector.IndexError) out of bound index: -9 not in -8..7``````

# pop_last(vector, default \\ nil)

View Source

## Specs

```pop_last(t(val), default) :: {val | default, t(val)}
when val: value(), default: term()```

Removes the last value from the `vector` and returns both the value and the updated vector.

Leaves the `vector` untouched if empty.

Runs in effective constant time.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> {8, updated} = A.Vector.pop_last(vector); updated
#A<vec([1, 2, 3, 4, 5, 6, 7])>
iex> {nil, updated} = A.Vector.pop_last(A.Vector.new()); updated
#A<vec([])>``````

# pop_last!(vector)

View Source

## Specs

`pop_last!(t(val)) :: {val, t(val)} when val: value()`

Removes the last value from the `vector` and returns both the value and the updated vector.

Raises an `A.Vector.EmptyError` if empty.

Runs in effective constant time.

## Examples

``````iex> vector = A.Vector.new(1..8)
iex> {8, updated} = A.Vector.pop_last!(vector); updated
#A<vec([1, 2, 3, 4, 5, 6, 7])>
iex> {nil, updated} = A.Vector.pop_last!(A.Vector.new()); updated
** (A.Vector.EmptyError) empty vector error``````

# prepend(vector, value)

View Source

## Specs

`prepend(t(val), val) :: t(val) when val: value()`

(Inefficient) Prepends `value` at the beginning of the `vector`.

Runs in linear time because the whole vector needs to be reconstructuded, and should be avoided.

## Examples

``````iex> A.Vector.new() |> A.Vector.prepend(:foo)
#A<vec([:foo])>
iex> A.Vector.new(1..5) |> A.Vector.prepend(:foo)
#A<vec([:foo, 1, 2, 3, 4, 5])>``````

# product(vector)

View Source

## Specs

`product(t(num)) :: num when num: number()`

Returns the product of all elements in the `vector`.

Raises `ArithmeticError` if `vector` contains a non-numeric value.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..5) |> A.Vector.product()
120
iex> A.Vector.new() |> A.Vector.product()
1``````

# reject(vector, fun)

View Source

## Specs

`reject(t(val), (val -> boolean())) :: t(val) when val: value()`

Filters the `vector`, i.e. return a new vector containing only elements for which `fun` returns a falsy (either `false` or `nil`) value.

Runs in linear time.

## Examples

``````iex> vector = A.Vector.new(1..12)
iex> A.Vector.reject(vector, fn i -> rem(i, 3) == 0 end)
#A<vec([1, 2, 4, 5, 7, 8, 10, 11])>``````

# repeatedly(generator_fun, n)

View Source

Populates a vector of size `n` by calling `generator_fun` repeatedly.

## Examples

``````# Although not necessary, let's seed the random algorithm
iex> :rand.seed(:exsplus, {1, 2, 3})
iex> A.Vector.repeatedly(&:rand.uniform/0, 3)
#A<vec([0.40502929729990744, 0.45336720247823126, 0.04094511692041057])>``````

# replace_at(vector, index, value)

View Source

## Specs

`replace_at(t(val), index(), val) :: t(val) when val: value()`

Returns a copy of `vector` with a replaced `value` at the specified `index`.

Returns the `vector` untouched if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new(1..8) |> A.Vector.replace_at(5, :foo)
#A<vec([1, 2, 3, 4, 5, :foo, 7, 8])>
iex> A.Vector.new(1..8) |> A.Vector.replace_at(8, :foo)
#A<vec([1, 2, 3, 4, 5, 6, 7, 8])>
iex> A.Vector.new(1..8) |> A.Vector.replace_at(-2, :foo)
#A<vec([1, 2, 3, 4, 5, 6, :foo, 8])>``````

# replace_at!(vector, index, value)

View Source

## Specs

`replace_at!(t(val), index(), val) :: t(val) when val: value()`

Returns a copy of `vector` with a replaced `value` at the specified `index`.

Raises an `A.Vector.IndexError` if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new(1..8) |> A.Vector.replace_at!(5, :foo)
#A<vec([1, 2, 3, 4, 5, :foo, 7, 8])>
iex> A.Vector.new(1..8) |> A.Vector.replace_at!(-2, :foo)
#A<vec([1, 2, 3, 4, 5, 6, :foo, 8])>
iex> A.Vector.new(1..8) |> A.Vector.replace_at!(8, :foo)
** (A.Vector.IndexError) out of bound index: 8 not in -8..7``````

# reverse(vector)

View Source

## Specs

`reverse(t(val)) :: t(val) when val: value()`

Returns the `vector` in reverse order.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..12) |> A.Vector.reverse()
#A<vec([12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1])>``````

# size(vector)

View Source

## Specs

`size(t()) :: non_neg_integer()`

Returns the number of elements in `vector`.

Runs in constant time.

## Examples

``````iex> A.Vector.new(10_000..20_000) |> A.Vector.size()
10001
iex> A.Vector.new() |> A.Vector.size()
0``````

# slice(vector, index_range)

View Source

## Specs

`slice(t(val), Range.t()) :: t(val) when val: value()`

Returns a subset of the given `vector` by `index_range`.

Works the same as `Enum.slice/2`, see its documentation for more details.

Runs in linear time regarding the size of the returned subset.

## Examples

``````iex> A.Vector.new(0..100) |> A.Vector.slice(80..90)
#A<vec([80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90])>
iex> A.Vector.new(0..100) |> A.Vector.slice(-40..-30)
#A<vec([61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71])>
iex> A.Vector.new([:only_one]) |> A.Vector.slice(0..1000)
#A<vec([:only_one])>``````

# slice(vector, start_index, amount)

View Source

## Specs

`slice(t(val), integer(), integer()) :: t(val) when val: value()`

Returns a subset of the given `vector`, from `start_index` (zero-based) with `amount number` of elements if available.

Works the same as `Enum.slice/3`, see its documentation for more details.

Runs in linear time regarding the size of the returned subset.

## Examples

``````iex> A.Vector.new(0..100) |> A.Vector.slice(80, 10)
#A<vec([80, 81, 82, 83, 84, 85, 86, 87, 88, 89])>
iex> A.Vector.new(0..100) |> A.Vector.slice(-40, 10)
#A<vec([61, 62, 63, 64, 65, 66, 67, 68, 69, 70])>
iex> A.Vector.new([:only_one]) |> A.Vector.slice(0, 1000)
#A<vec([:only_one])>``````

# sort(vector)

View Source

## Specs

`sort(t(val)) :: t(val) when val: value()`

Sorts the `vector` in the same way as `Enum.sort/1`.

## Examples

``````iex> A.Vector.new(9..1) |> A.Vector.sort()
#A<vec([1, 2, 3, 4, 5, 6, 7, 8, 9])>``````

# sort(vector, fun)

View Source

## Specs

```sort(
t(val),
(val, val -> boolean()) | :asc | :desc | module() | {:asc | :desc, module()}
) :: t(val)
when val: value()```

Sorts the `vector` in the same way as `Enum.sort/2`.

See `Enum.sort/2` documentation for detailled usage.

## Examples

``````iex> A.Vector.new(1..9) |> A.Vector.sort(:desc)
#A<vec([9, 8, 7, 6, 5, 4, 3, 2, 1])>``````

# sort_by(vector, mapper, sorter \\ &<=/2)

View Source

## Specs

```sort_by(
t(val),
(val -> mapped_val),
(val, val -> boolean()) | :asc | :desc | module() | {:asc | :desc, module()}
) :: t(val)
when val: value(), mapped_val: value()```

Sorts the `vector` in the same way as `Enum.sort_by/3`.

See `Enum.sort_by/3` documentation for detailled usage.

## Examples

``````iex> vector = A.Vector.new(["some", "kind", "of", "monster"])
iex> A.Vector.sort_by(vector, &byte_size/1)
#A<vec(["of", "some", "kind", "monster"])>
iex> A.Vector.sort_by(vector, &{byte_size(&1), String.first(&1)})
#A<vec(["of", "kind", "some", "monster"])>``````

# sum(vector)

View Source

## Specs

`sum(t(num)) :: num when num: number()`

Returns the sum of all elements in the `vector`.

Raises `ArithmeticError` if `vector` contains a non-numeric value.

Runs in linear time.

## Examples

``````iex> A.Vector.new(1..10) |> A.Vector.sum()
55
iex> A.Vector.new() |> A.Vector.sum()
0``````

# take(vector, amount)

View Source

## Specs

`take(t(val), integer()) :: t(val) when val: value()`

Takes an `amount` of elements from the beginning or the end of the `vector`.

If a positive `amount` is given, it takes the amount elements from the beginning of the `vector`.

If a negative `amount` is given, the amount of elements will be taken from the end.

If amount is 0, it returns the empty vector.

Time complexity is:

• effective constant time when `amount` is positive, as the vector structure can be shared
• linear when `amount` is negative, as the vector needs to be reconstructed.

## Examples

``````iex> A.Vector.new(0..100) |> A.Vector.take(10)
#A<vec([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>
iex> A.Vector.new([:only_one]) |> A.Vector.take(1000)
#A<vec([:only_one])>
iex> A.Vector.new(0..10) |> A.Vector.take(-5)
#A<vec([6, 7, 8, 9, 10])>``````

# to_list(vector)

View Source

## Specs

`to_list(t(val)) :: [val] when val: value()`

Converts the `vector` to a list.

Runs in linear time.

## Examples

``````iex> A.Vector.new(10..25) |> A.Vector.to_list()
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
iex> A.Vector.new() |> A.Vector.to_list()
[]``````

# uniq(vector)

View Source

## Specs

`uniq(t(val)) :: t(val) when val: value()`

Returns a copy of the vector without any duplicated element.

The first occurrence of each element is kept.

Runs in linear time.

## Examples

``````iex> A.Vector.new([1, 1, 2, 1, 2, 3, 2]) |> A.Vector.uniq()
#A<vec([1, 2, 3])>``````

# uniq_by(vector, fun)

View Source

## Specs

`uniq_by(t(val), (val -> term())) :: t(val) when val: value()`

Returns a copy of the vector without elements for which the function `fun` returned duplicate elements.

The first occurrence of each element is kept.

Runs in linear time.

## Examples

``````iex> vector = A.Vector.new([x: 1, y: 2, z: 1])
#A<vec([x: 1, y: 2, z: 1])>
iex> A.Vector.uniq_by(vector, fn {_x, y} -> y end)
#A<vec([x: 1, y: 2])>``````

# update_at(vector, index, fun)

View Source

## Specs

`update_at(t(val), index(), (val -> val)) :: t(val) when val: value()`

Returns a copy of `vector` with an updated value at the specified `index`.

Returns the `vector` untouched if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new(1..8) |> A.Vector.update_at(2, &(&1 * 1000))
#A<vec([1, 2, 3000, 4, 5, 6, 7, 8])>
iex> A.Vector.new(1..8) |> A.Vector.update_at(8, &(&1 * 1000))
#A<vec([1, 2, 3, 4, 5, 6, 7, 8])>
iex> A.Vector.new(1..8) |> A.Vector.update_at(-1, &(&1 * 1000))
#A<vec([1, 2, 3, 4, 5, 6, 7, 8000])>``````

# update_at!(vector, index, fun)

View Source

## Specs

`update_at!(t(val), index(), (val -> val)) :: t(val) when val: value()`

Returns a copy of `vector` with an updated value at the specified `index`.

Raises an `A.Vector.IndexError` if `index` is out of bounds. Supports negative indexing from the end of the `vector`.

Runs in effective constant time.

## Examples

``````iex> A.Vector.new(1..8) |> A.Vector.update_at!(2, &(&1 * 1000))
#A<vec([1, 2, 3000, 4, 5, 6, 7, 8])>
iex> A.Vector.new(1..8) |> A.Vector.update_at!(-1, &(&1 * 1000))
#A<vec([1, 2, 3, 4, 5, 6, 7, 8000])>
iex> A.Vector.new(1..8) |> A.Vector.update_at!(-9, &(&1 * 1000))
** (A.Vector.IndexError) out of bound index: -9 not in -8..7``````