Skip to content

arrays #

Description

arrays is a module that provides utility functions to make working with arrays easier.

See combinatorics for permutations, combinations, and Cartesian products.

Examples

import arrays

fn main() {
    a := [1, 5, 7, 0, 9]
    assert arrays.min(a)! == 0
    assert arrays.max(a)! == 9
    assert arrays.idx_min(a)! == 3
}

lower_bound, upper_bound, and binary_search return an error when no matching element exists. The error names the operation and the value that could not be found.

chunk(array, size) returns an empty array when size is zero or negative.

is_sorted(array) checks ascending order, allowing equal adjacent elements. Empty and single-element arrays are sorted. The element type must support ordering comparisons. bisect_left(array, value) and bisect_right(array, value) return insertion positions in an ascending sorted array, before or after existing equal values. insort_left and insort_right insert at those positions. Empty arrays return position zero; unsorted input is unsupported.

group zips its input arrays into rows. A single array is one input: arrays.group([1, 2]) returns [[1], [2]]. To supply an array of inputs, spread it with arrays.group(...inputs). Generic element types can be inferred from the input arrays, including inside interpolation.

Nested arrays follow the same rule: arrays.group([[1, 2], [3, 4]]) returns [[[1, 2]], [[3, 4]]], while arrays.group(...[[1, 2], [3, 4]]) returns [[1, 3], [2, 4]].

fn append #

fn append[T](a []T, b []T) []T

append the second array b to the first array a, and return the result. Note, that unlike arrays.concat, arrays.append is less flexible, but more efficient, since it does not require you to use ...a for the second parameter.

Example

arrays.append([1, 3, 5, 7], [2, 4, 6, 8]) // => [1, 3, 5, 7, 2, 4, 6, 8]

fn bisect_left #

fn bisect_left[T](array []T, val T) int

bisect_left returns the leftmost index where val could be inserted into the ascending-sorted array keeping it sorted: the index of the first element >= val. It is the V-idiomatic equivalent of Python's bisect.bisect_left / Go's sort.Search. Unsorted input yields an undefined (but memory-safe) result, matching both languages.

fn bisect_right #

fn bisect_right[T](array []T, val T) int

bisect_right returns the rightmost insertion index: the index of the first element > val. It is the V-idiomatic equivalent of Python's bisect.bisect_right (a.k.a. bisect).

fn carray_to_varray #

@[unsafe]
fn carray_to_varray[T](c_array_data voidptr, items int) []T

carray_to_varray copies a C byte array into a V array of type T. See also: cstring_to_vstring

fn chunk #

fn chunk[T](array []T, size int) [][]T

It returns an empty array, when size is not positive.

Example

arrays.chunk([1, 2, 3, 4, 5, 6, 7, 8, 9], 2) // => [[1, 2], [3, 4], [5, 6], [7, 8], [9]]

fn chunk_while #

fn chunk_while[T](a []T, predicate fn (before T, after T) bool) [][]T

chunk_while splits the input array a into chunks of varying length, using the predicate, passing to it pairs of adjacent elements before and after. Each chunk, will contain all ajdacent elements, for which the predicate returned true. The chunks are split between the before and after elements, for which the predicate returned false.

Examples

assert arrays.chunk_while([0,9,2,2,3,2,7,5,9,5],fn(x int,y int)bool{return x<=y})==[[0,9],[2,2,3],[2,7],[5,9],[5]]
assert arrays.chunk_while('aaaabbbcca'.runes(),fn(x rune,y rune)bool{return x==y})==[[`a`,`a`,`a`,`a`],[`b`,`b`,`b`],[`c`,`c`],[`a`]]
assert arrays.chunk_while('aaaabbbcca'.runes(),fn(x rune,y rune)bool{return x==y}).map({it[0]:it.len})==[{`a`:4},{`b`:3},{`c`:2},{`a`:1}]

fn combinations #

fn combinations[T](items []T, k int) [][]T

combinations returns all C(n, k) k-sized subsets of items in input-index order. Out-of-range k yields no rows; k == 0 yields one empty row. It is the V-idiomatic equivalent of Python's itertools.combinations.

fn concat #

fn concat[T](a []T, b ...T) []T

concatenate an array with an arbitrary number of additional values.

Note: if you have two arrays, you should simply use the << operator directly.

Examples

assert arrays.concat([1, 2, 3], 4, 5, 6) == [1, 2, 3, 4, 5, 6]
assert arrays.concat([1, 2, 3], ...[4, 5, 6]) == [1, 2, 3, 4, 5, 6]
mut arr := arrays.concat([1, 2, 3], 4); arr << [10,20]; assert arr == [1,2,3,4,10,20] // note: arr is mutable

fn copy #

fn copy[T](mut dst []T, src []T) int

copy copies the src array elements to the dst array. The number of the elements copied is the minimum of the length of both arrays. The src and dst arrays may overlap. Returns the number of elements copied.

fn distinct #

fn distinct[T](a []T) []T

distinct returns all distinct elements from the given array a. The results are guaranteed to be unique, i.e. not have duplicates. See also arrays.uniq, which can be used to achieve the same goal, but needs you to first sort the array.

Example

assert arrays.distinct( [5, 5, 1, 5, 2, 1, 1, 9] ) == [1, 2, 5, 9]

fn each #

fn each[T](a []T, cb fn (elem T))

each calls the callback fn cb, for each element of the given array a.

fn each_indexed #

fn each_indexed[T](a []T, cb fn (i int, e T))

each_indexed calls the callback fn cb, for each element of the given array a. It passes the callback both the index of the current element, and the element itself.

fn filter_indexed #

fn filter_indexed[T](array []T, predicate fn (idx int, elem T) bool) []T

filter_indexed filters elements based on predicate function being invoked on each element with its index in the original array.

fn find_first #

fn find_first[T](array []T, predicate fn (elem T) bool) ?T

find_first returns the first element that matches the given predicate. Returns none if no match is found.

Example

arrays.find_first([1, 2, 3, 4, 5], fn (i int) bool { return i == 3 })? // => 3

fn find_last #

fn find_last[T](array []T, predicate fn (elem T) bool) ?T

find_last returns the last element that matches the given predicate. Returns none if no match is found.

Example

arrays.find_last([1, 2, 3, 4, 5], fn (i int) bool { return i == 3})? // => 3

fn flat_map #

fn flat_map[T, R](array []T, transform fn (elem T) []R) []R

flat_map creates a new array populated with the flattened result of calling transform function being invoked on each element of list.

fn flat_map_indexed #

fn flat_map_indexed[T, R](array []T, transform fn (idx int, elem T) []R) []R

flat_map_indexed creates a new array with the flattened result of calling the transform fn, invoked on each idx,elem pair from the original.

fn flatten #

fn flatten[T](array [][]T) []T

flatten flattens n + 1 dimensional array into n dimensional array.

Example

arrays.flatten[int]([[1, 2, 3], [4, 5]]) // => [1, 2, 3, 4, 5]

fn fold #

fn fold[T, R](array []T, init R, fold_op fn (acc R, elem T) R) R

fold sets acc = init, then successively calls acc = fold_op(acc, elem) for each element in array. returns acc.

Example

// Sum the length of each string in an array
a := ['Hi', 'all']
r := arrays.fold[string, int](a, 0,
	fn (r int, t string) int { return r + t.len })
assert r == 5

fn fold_indexed #

fn fold_indexed[T, R](array []T, init R, fold_op fn (idx int, acc R, elem T) R) R

fold_indexed sets acc = init, then successively calls acc = fold_op(idx, acc, elem) for each element in array. returns acc.

fn group #

fn group[T](arrs ...[]T) [][]T

group n arrays into a single array of arrays with n elements. This function is analogous to the "zip" function of other languages. To fully interleave two arrays, follow this function with a call to flatten. A single input array produces one-element groups: arrays.group([1, 2]) == [[1], [2]].

Example

arrays.group[int]([1, 2, 3], [4, 5, 6]) // => [[1, 4], [2, 5], [3, 6]]

fn group_by #

fn group_by[K, V](array []V, grouping_op fn (val V) K) map[K][]V

group_by groups together elements, for which the grouping_op callback produced the same result.

Example

arrays.group_by[int, string](['H', 'el', 'lo'], fn (v string) int { return v.len }) // => {1: ['H'], 2: ['el', 'lo']}

fn idx_max #

fn idx_max[T](array []T) !int

idx_max returns the index of the maximum value in the array.

Example

arrays.idx_max([1, 2, 3, 0, 9])! // => 4

fn idx_min #

fn idx_min[T](array []T) !int

idx_min returns the index of the minimum value in the array.

Example

arrays.idx_min([1, 2, 3, 0, 9])! // => 3

fn index_of_first #

fn index_of_first[T](array []T, predicate fn (idx int, elem T) bool) int

index_of_first returns the index of the first element of array, for which the predicate fn returns true. If predicate does not return true for any of the elements, then index_of_first will return -1.

Example

assert arrays.index_of_first([4,5,0,7,0,9], fn(idx int, x int) bool { return x == 0 }) == 2

fn index_of_last #

fn index_of_last[T](array []T, predicate fn (idx int, elem T) bool) int

index_of_last returns the index of the last element of array, for which the predicate fn returns true. If predicate does not return true for any of the elements, then index_of_last will return -1.

Example

assert arrays.index_of_last([4,5,0,7,0,9], fn(idx int, x int) bool { return x == 0 }) == 4

fn insort_left #

fn insort_left[T](mut array []T, val T)

insort_left inserts val into the ascending-sorted array at the bisect_left position, keeping it sorted.

fn insort_right #

fn insort_right[T](mut array []T, val T)

insort_right inserts val into the ascending-sorted array at the bisect_right position, keeping it sorted (equal values go after existing ones).

fn is_sorted #

fn is_sorted[T](a []T) bool

is_sorted reports whether a is in non-descending order (a[i-1] <= a[i]). The empty and single-element arrays are sorted. It is the V-idiomatic equivalent of Go's slices.IsSorted.

fn join_to_string #

@[manualfree]
fn join_to_string[T](array []T, separator string, transform fn (elem T) string) string

join_to_string takes in a custom transform function and joins all elements into a string with the specified separator

fn lower_bound #

fn lower_bound[T](array []T, val T) !T

lower_bound returns the smallest element >= val, requiring array to be sorted. An empty array or missing bound returns an error describing the operation and value.

Example

arrays.lower_bound([2, 4, 6, 8], 3)! // => 4

fn map_indexed #

fn map_indexed[T, R](array []T, transform fn (idx int, elem T) R) []R

map_indexed creates a new array with the result of calling the transform fn, invoked on each idx,elem pair from the original.

fn map_of_counts #

fn map_of_counts[T](array []T) map[T]int

map_of_counts returns a map, where each key is an unique value in array. Each value in that map for that key, is how many times that value occurs in array. It can be useful for building histograms of discrete measurements.

Example

assert arrays.map_of_counts([1,2,3,4,4,2,1,4,4]) == {1: 2, 2: 2, 3: 1, 4: 4}

fn map_of_indexes #

fn map_of_indexes[T](array []T) map[T][]int

map_of_indexes returns a map, where each key is an unique value in array. Each value in that map for that key, is an array, containing the indexes in array, where that value has been found.

Example

assert arrays.map_of_indexes([1,2,3,4,4,2,1,4,4,999]) == {1: [0, 6], 2: [1, 5], 3: [2], 4: [3, 4, 7, 8], 999: [9]}

fn max #

fn max[T](array []T) !T

max returns the maximum value in the array.

Example

arrays.max([1, 2, 3, 0, 9])! // => 9

fn merge #

@[direct_array_access]
fn merge[T](a []T, b []T) []T

merge two sorted arrays (ascending) and maintain sorted order.

Example

arrays.merge([1, 3, 5, 7], [2, 4, 6, 8]) // => [1, 2, 3, 4, 5, 6, 7, 8]

fn merge_desc #

@[direct_array_access]
fn merge_desc[T](a []T, b []T) []T

merge_desc merges two sorted arrays (descending) and maintains sorted order.

Example

arrays.merge_desc([7, 5, 3, 1], [8, 6, 4, 2]) // => [8, 7, 6, 5, 4, 3, 2, 1]

fn min #

fn min[T](array []T) !T

min returns the minimum value in the array.

Example

arrays.min([1, 2, 3, 0, 9])! // => 0

fn partition #

fn partition[T](array []T, predicate fn (elem T) bool) ([]T, []T)

partition splits the original array into pair of lists. The first list contains elements for which the predicate fn returned true, while the second list contains elements for which the predicate fn returned false.

fn permutations #

fn permutations[T](items []T) [][]T

permutations returns all n! orderings of items (Heap's algorithm, iterative, O(n) auxiliary space). The empty input yields one empty permutation. It is the V-idiomatic equivalent of Python's itertools.permutations.

fn product #

fn product[T](a []T, b []T) [][]T

product returns the cartesian product of a and b: one [x, y] row per pair. It is the V-idiomatic equivalent of Python's itertools.product for the single-type case.

fn reduce #

fn reduce[T](array []T, reduce_op fn (acc T, elem T) T) !T

reduce sets acc = array[0], then successively calls acc = reduce_op(acc, elem) for each remaining element in array. returns the accumulated value in acc. returns an error if the array is empty. See also: fold.

Example

arrays.reduce([1, 2, 3, 4, 5], fn (t1 int, t2 int) int { return t1 * t2 })! // => 120

fn reduce_indexed #

fn reduce_indexed[T](array []T, reduce_op fn (idx int, acc T, elem T) T) !T

reduce_indexed sets acc = array[0], then successively calls acc = reduce_op(idx, acc, elem) for each remaining element in array. returns the accumulated value in acc. returns an error if the array is empty. See also: fold_indexed.

fn reverse_iterator #

fn reverse_iterator[T](a []T) ReverseIterator[T]

reverse_iterator can be used to iterate over the elements in an array. i.e. you can use this syntax: for elem in arrays.reverse_iterator(a) { .

fn rotate_left #

fn rotate_left[T](mut array []T, mid int)

rotate_left rotates the array in-place. It does it in such a way, that the first mid elements of the array, move to the end, while the last array.len - mid elements move to the front. After calling rotate_left, the element previously at index mid will become the first element in the array.

Example

mut x := [1,2,3,4,5,6]
arrays.rotate_left(mut x, 2)
println(x) // [3, 4, 5, 6, 1, 2]

fn rotate_right #

fn rotate_right[T](mut array []T, k int)

rotate_right rotates the array in-place. It does it in such a way, that the first array.len - k elements of the array, move to the end, while the last k elements move to the front. After calling rotate_right, the element previously at index array.len - k will become the first element in the array.

Example

mut x := [1,2,3,4,5,6]
arrays.rotate_right(mut x, 2)
println(x) // [5, 6, 1, 2, 3, 4]

fn sum #

fn sum[T](array []T) !T

sum up array, return an error, when the array has no elements.

Example

arrays.sum([1, 2, 3, 4, 5])! // => 15

fn uniq #

fn uniq[T](a []T) []T

uniq filters the adjacent matching elements from the given array. All adjacent matching elements, are merged to their first occurrence, so the output will have no repeating elements.

Note: uniq does not detect repeats, unless they are adjacent. You may want to call a.sorted() on your array, before passing the result to arrays.uniq(). See also arrays.distinct, which is essentially arrays.uniq(a.sorted()) .

Examples

assert arrays.uniq( []int{} ) == []
assert arrays.uniq( [1, 1] ) == [1]
assert arrays.uniq( [2, 1] ) == [2, 1]
assert arrays.uniq( [5, 5, 1, 5, 2, 1, 1, 9] ) == [5, 1, 5, 2, 1, 9]

fn uniq_all_repeated #

fn uniq_all_repeated[T](a []T) []T

uniq_all_repeated produces all adjacent matching elements from the given array. Unique elements, with no duplicates are removed. The output will contain all the duplicated elements, repeated just like they were in the original.

Note: uniq_all_repeated does not detect repeats, unless they are adjacent. You may want to call a.sorted() on your array, before passing the result to arrays.uniq_all_repeated().

Examples

assert arrays.uniq_all_repeated( []int{} ) == []
assert arrays.uniq_all_repeated( [1, 5] ) == []
assert arrays.uniq_all_repeated( [5, 5] ) == [5,5]
assert arrays.uniq_all_repeated( [5, 5, 1, 5, 2, 1, 1, 9] ) == [5, 5, 1, 1]

fn uniq_only #

fn uniq_only[T](a []T) []T

uniq_only filters the adjacent matching elements from the given array. All adjacent matching elements, are removed. The output will contain only the elements that did not have any adjacent matches.

Note: uniq_only does not detect repeats, unless they are adjacent. You may want to call a.sorted() on your array, before passing the result to arrays.uniq_only().

Examples

assert arrays.uniq_only( []int{} ) == []
assert arrays.uniq_only( [1, 1] ) == []
assert arrays.uniq_only( [2, 1] ) == [2, 1]
assert arrays.uniq_only( [1, 5, 5, 1, 5, 2, 1, 1, 9] ) == [1, 1, 5, 2, 9]

fn uniq_only_repeated #

fn uniq_only_repeated[T](a []T) []T

uniq_only_repeated produces the adjacent matching elements from the given array. Unique elements, with no duplicates are removed. Adjacent matching elements, are reduced to just 1 element per repeat group.

Note: uniq_only_repeated does not detect repeats, unless they are adjacent. You may want to call a.sorted() on your array, before passing the result to arrays.uniq_only_repeated().

Examples

assert arrays.uniq_only_repeated( []int{} ) == []
assert arrays.uniq_only_repeated( [1, 5] ) == []
assert arrays.uniq_only_repeated( [5, 5] ) == [5]
assert arrays.uniq_only_repeated( [5, 5, 1, 5, 2, 1, 1, 9] ) == [5, 1]

fn upper_bound #

fn upper_bound[T](array []T, val T) !T

upper_bound returns the largest element <= val, requiring array to be sorted. An empty array or missing bound returns an error describing the operation and value.

Example

arrays.upper_bound([2, 4, 6, 8], 3)! // => 2

fn window #

fn window[T](array []T, attr WindowAttribute) [][]T

window returns fixed-size windows over array. Each window starts attr.step positions after the previous window. It returns an empty array when the input or attributes cannot produce a window.

Examples

arrays.window([1, 2, 3, 4], size: 2) // => [[1, 2], [2, 3], [3, 4]]
arrays.window([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], size: 3, step: 2) // => [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]]

fn (ReverseIterator[T]) next #

@[direct_array_access]
fn (mut iter ReverseIterator[T]) next() ?&T

next is the required method, to implement an iterator in V. It returns none when the iteration should stop. Otherwise it returns the current element of the array.

fn (ReverseIterator[T]) free #

fn (iter &ReverseIterator[T]) free()

free frees the iterator resources.

struct ReverseIterator #

struct ReverseIterator[T] {
mut:
	a []T
	i int
}

ReverseIterator provides a convenient way to iterate in reverse over all elements of an array without allocations. I.e. it allows you to use this syntax: for elem in arrays.reverse_iterator(a) { .

struct WindowAttribute #

struct WindowAttribute {
pub:
	size int // number of elements in each window; must be positive
	step int = 1 // amount added to the starting index after each window; must be positive
}

WindowAttribute configures the windows produced by arrays.window.