array_vector v0.3.0 Vector

Functions that work on vectors.

This datastructure wraps Erlang’s array type for fast random lookup and update to large collections.

The point of this module is not meant to be a 1:1 wrapper, but to be a useful set of higher-level API operations.

Note that this module is implemented as a struct with an array field, pointing to the underlying Erlang array implementation. This field is private, so you should use the functions in this module to perform operations.

Link to this section Summary

Functions

Append an item to to a vector

Returns the count of initialized elements in the vector. Does not count uninitialized elements. This function takes time linear to the number of uninitialized elements

Returns either the vector without the value at index, or the original vector if no value is present at index

Finds the element at the given index (zero-based) in logarithmic time. Returns {:ok, element} if found, otherwise :error

Finds the element at the given index (zero-based) in logarithmic time

Gets the value at an index in logarithmic time, returning a default if it does not exist

Gets and updates a value at the same time

Run a function over the elements of the vector, not including the uninitialized ones, and return the result in a new vector. Good for large vectors where only a few elements are set

Checks if vector contains value

Constructs a array-backed vector

Deletes a value at index, returning the new vector and the value that was deleted

Puts the given value under index in vector in logarithmic time

Run a function (fun) over a vector which takes two arguments: the accumulated results so far (acc) and the current vector value (val). Hits only the initialized elements of the vector. Note that fun is arity-3, taking the index, value, and acc in that order

Reverse every element in a vector, not including the uninitialized elements. Preserves count, does not preserve size

Returns the total size of a vector, including all uninitialized/default values

Converts a vector to a list

Updates the value in vector with the given function in logarithmic time

Updates index with the given function in logarithmic time

Link to this section Types

Link to this type acc()
acc() :: any
Link to this type array_reducing_fn()
array_reducing_fn() :: (non_neg_integer, value, acc -> acc)
Link to this type index()
index() :: integer
Link to this type value()
value() :: any

Link to this section Functions

Link to this function append(vector, value)
append(t, value) :: t

Append an item to to a vector

Examples

iex> Vector.new([1, 2, 3]) |> Vector.append(9)
Vector.new([1, 2, 3, 9])

iex> Vector.new() |> Vector.append("hi")
Vector.new(["hi"])

iex> Vector.new([1, 2, 3]) |> Vector.append(9) |> Vector.size
4
Link to this function count(vector)
count(t) :: non_neg_integer

Returns the count of initialized elements in the vector. Does not count uninitialized elements. This function takes time linear to the number of uninitialized elements.

Examples

iex> Vector.count(Vector.new())
0

iex> Vector.count(Vector.new([1,2,3,4,5]))
5

iex> Vector.new(100) |> Vector.count
0

iex> Vector.new(100)
...> |> Vector.put(43, 1)
...> |> Vector.count
1
Link to this function delete(vector, index)
delete(t, index) :: t

Returns either the vector without the value at index, or the original vector if no value is present at index.

Examples

iex> Vector.delete(Vector.new([1,2,3,4,5]), 2)
#Vector<[1, 2, 4, 5]>

iex> Vector.delete(Vector.new([1,2,3]), 9)
#Vector<[1, 2, 3]>
Link to this function fetch(vector, index)
fetch(t, index) :: {:ok, any} | :error

Finds the element at the given index (zero-based) in logarithmic time. Returns {:ok, element} if found, otherwise :error.

A negative index can be passed, in which case the index is counted from the end (e.g. -1 finds the last element).

Examples

iex> Vector.fetch(Vector.new([1,2,3]), 9)
:error

iex> Vector.fetch(Vector.new([1,2,3]), 2)
{:ok, 3}

iex> Vector.fetch(Vector.new([1,2,3,4,5]), -2)
{:ok, 4}

iex> Vector.fetch(Vector.new([1,2,3,4,5]), -6)
:error
Link to this function fetch!(vector, index)
fetch!(t, index) :: value | no_return

Finds the element at the given index (zero-based) in logarithmic time.

Raises OutOfBoundsError if the given index is outside the range of the enumerable.

A negative index can be passed, in which case the index is counted from the end (e.g. -1 finds the last element).

Examples

iex> Vector.fetch!(Vector.new([1,2,3]), 1)
2

iex> Vector.fetch!(Vector.new([1,2,3]), -1)
3

iex> Vector.fetch!(Vector.new([1,2,3]), 99)
** (Enum.OutOfBoundsError) out of bounds error
Link to this function get(vector, index, default \\ nil)
get(t, index, default :: value) :: value

Gets the value at an index in logarithmic time, returning a default if it does not exist.

Examples

iex> Vector.get(Vector.new([1,2,3]), 0)
1

iex> Vector.get(Vector.new([1,2,3]), 9)
nil

iex> Vector.get(Vector.new([1,2,3]), 9, 1000)
1000
Link to this function get_and_update(vector, index, fun)
get_and_update(t, index, (value -> {value, value} | :pop)) :: {value, t}

Gets and updates a value at the same time.

Examples

iex> {val, new_vector} = Vector.get_and_update(Vector.new([1,2,3]), 0, fn(value) -> {value, value + 100} end)
iex> {val, Vector.to_list(new_vector)}
{1, [101, 2, 3]}

iex> {val, new_vector} = Vector.get_and_update(Vector.new([1,2,3]), 0, fn(_) -> :pop end)
iex> {val, Vector.to_list(new_vector)}
{1, [2, 3]}
Link to this function map(vector, fun)

Run a function over the elements of the vector, not including the uninitialized ones, and return the result in a new vector. Good for large vectors where only a few elements are set.

Examples

iex> Vector.new() |> Vector.map(fn(_i, val) -> val + 1 end)
#Vector<[]>

iex> Vector.new([1, 2, 3]) |> Vector.map(fn(_i, val) -> val + 1 end)
#Vector<[2, 3, 4]>

iex> Vector.new(100) |> Vector.map(fn(_i, _val) -> 1 end) |> Enum.sum
0
Link to this function member?(vector, value)

Checks if vector contains value

Examples

iex> Vector.member?(Vector.new([1,2,3]), 99)
false

iex> Vector.member?(Vector.new([1,2,3]), 2)
true

Constructs a array-backed vector

Examples

iex> Vector.new()
#Vector<[]>

iex> Vector.new(Vector.new())
#Vector<[]>

iex> Vector.new([1,2,3])
#Vector<[1, 2, 3]>

iex> Vector.new(%{a: 1, b: 2})
#Vector<[a: 1, b: 2]>

iex> Vector.new(0)
#Vector<[]>

# this is exposing a bit of implementation, but I am
# unsure how else to test it
iex> Vector.new(5).array
{:array, 5, 10, :undefined, 10}
Link to this function pop(vector, index, default \\ nil)

Deletes a value at index, returning the new vector and the value that was deleted

Examples

iex> {value, new} = Vector.pop(Vector.new([1,2,3]), 2)
iex> {value, Vector.to_list(new)} # arrays cannot be checked for value equality
{3, [1, 2]}

iex> {value, new} = Vector.pop(Vector.new([1,2,3]), 99)
iex> {value, Vector.to_list(new)}
{nil, [1, 2, 3]}
Link to this function put(vector, index, value)
put(t, index, value) :: t

Puts the given value under index in vector in logarithmic time

A negative index can be passed, in which case the index is counted from the end (e.g. -1 finds the last element).

Examples

iex> Vector.put(Vector.new([1,2,3]), 3, 99)
#Vector<[1, 2, 3, 99]>

iex> Vector.put(Vector.new([1,2,3]), 0, 3)
#Vector<[3, 2, 3]>

iex> Vector.put(Vector.new([1,2,3]), -1, 101)
#Vector<[1, 2, 101]>

iex> Vector.put(Vector.new(3), -99, "hi")
** (ArgumentError) negative index out of bounds
Link to this function reduce(vector, initial, fun)
reduce(t, acc, array_reducing_fn) :: acc

Run a function (fun) over a vector which takes two arguments: the accumulated results so far (acc) and the current vector value (val). Hits only the initialized elements of the vector. Note that fun is arity-3, taking the index, value, and acc in that order.

Think of this function as the equivalent of the following pseudocode:

vector |> filter(initialized?) |> reduce

without the intermediate filter, due to sparse folding being an array primitive.

Examples

iex> Vector.new([1, 2, 3]) |> Vector.reduce(0, fn(_index, val, acc) -> val + acc end)
6

iex> Vector.new([1, 2, 3]) |> Vector.reduce(Vector.new(), fn(_index, val, acc) -> Vector.append(acc, val + 1) end)
#Vector<[2, 3, 4]>

iex> Vector.new(100)
...> |> Vector.put(25, 1)
...> |> Vector.put(50, 1)
...> |> Vector.put(75, 1)
...> |> Vector.put(90, 1)
...> |> Vector.reduce(0, fn(_index, val, acc) -> acc + val end)
4
Link to this function reverse(vector)
reverse(t) :: t

Reverse every element in a vector, not including the uninitialized elements. Preserves count, does not preserve size.

Examples

iex> vector = Vector.new([1,2,3])
iex> vector |> Vector.reverse |> Vector.reverse
#Vector<[1, 2, 3]>

iex> Vector.reverse(Vector.new())
#Vector<[]>

iex> Vector.reverse(Vector.new([1, 2, 3]))
#Vector<[3, 2, 1]>

iex> vector = Vector.new(50) |> Vector.put(39, "hi")
iex> reversed = Vector.reverse(vector)
iex> Vector.count(vector) == Vector.count(reversed)
true

Returns the total size of a vector, including all uninitialized/default values.

This function is a reflection of the total memory size of the underlying Erlang array. It does not say anything about the elements of the array. For a count of non-default elements in the vector, see count/1.

Examples

iex> Vector.size(Vector.new())
0

iex> Vector.size(Vector.new([1,2,3,4,5]))
5

iex> Vector.new(100) |> Vector.size
100

iex> Vector.new(100) |> Vector.put(43, 1) |> Vector.size
100
Link to this function to_list(vector)

Converts a vector to a list

Examples

iex> Vector.new() |> Vector.to_list
[]

iex> Vector.to_list(Vector.new([1,2,3]))
[1,2,3]

iex> Vector.new(100) |> Vector.put(39, 1) |> Vector.to_list
[1]
Link to this function update(vector, index, initial, fun)
update(t, index, value, (value -> value)) :: t

Updates the value in vector with the given function in logarithmic time.

If index is present in vector with value, fun is invoked with argument value and its result is used as the new value of index. If index is not present in vector, initial is inserted as the value of index.

A negative index can be passed, in which case the index is counted from the end (e.g. -1 finds the last element).

Examples

iex> Vector.update(Vector.new([1,2,3]), 0, 13, &(&1 * 2))
#Vector<[2, 2, 3]>

iex> Vector.update(Vector.new([1,2,3]), 5, 11, &(&1 * 2))
#Vector<[1, 2, 3, 11]>

iex> Vector.update(Vector.new([1,2,3]), -2, 11, &(&1 * 2))
#Vector<[1, 4, 3]>
Link to this function update!(vector, index, fun)
update!(t, index, (value -> value)) :: t | no_return

Updates index with the given function in logarithmic time.

If index is present in vector with value, fun is invoked with argument value and its result is used as the new value of index. If index is not present in vector, a Enum.OutOfBoundsError exception is raised.

Examples

iex> Vector.update!(Vector.new([1,2,3]), 0, &(&1 * 2))
#Vector<[2, 2, 3]>

iex> Vector.update!(Vector.new([1,2,3]), 5, &(&1 * 2))
** (Enum.OutOfBoundsError) out of bounds error

iex> Vector.update!(Vector.new([1,2,3]), -2, &(&1 * 2))
#Vector<[1, 4, 3]>