Vector¶
The default sequence, like ZIO's Chunk. A Vector is a tree of arrays of 32 elements, at most six levels deep.
Access by index, update, adding at either end, take, drop and slice are "effectively O(1)": they read or copy
a few small arrays whatever the size, because the tree is never more than six levels deep. A result shares every other
element with the original.
The first and the last leaves are kept apart from the rest of the tree. So head and last read one array, and
prepend and append usually copy one leaf of at most 32 elements.
Concatenating two vectors reuses the arrays of the longer one: only the shorter one is copied.
Elements are always stored as objects: Vector.ofAll(int...) and Vector.range box every value.
When to choose it¶
Whenever you need a sequence and have no reason to pick another one. Access by index, updates, adding at either end,
take, drop, slice and bulk operations are all cheap.
Choose another sequence for a specific need:
Listto take a sequence apart from the front with pattern matching;Queuefor first in, first out;LazyListfor a lazy or infinite sequence.
var letters = Vector.of("a", "b", "c", "d");
var changed = letters.update(1, "B").prepend("z").drop(2); // Vector<String>
var halves = letters.splitAt(2); // Tuple2<Vector<String>, Vector<String>>
// changed is Vector(B, c, d), halves is (Vector(a, b), Vector(c, d))
var numbers = Vector.range(0, 10); // Vector<Integer>
var windows = numbers.sliding(3, 3); // Vector<Vector<Integer>>
var parts = numbers.partitionMap( // Tuple2<Vector<Integer>, Vector<String>>
n -> n % 2 == 0 ? Either.left(n) : Either.right("odd " + n));
// windows is Vector(Vector(0, 1, 2), Vector(3, 4, 5), Vector(6, 7, 8), Vector(9))
Costs¶
| Operation | Cost | Note |
|---|---|---|
head |
O(1) | O(1): the first elements are kept apart, in their own array. |
tail |
effectively O(1) | effectively O(1): the first array, at most 32 elements, is copied without its first element; the few arrays above it change only when it held one element. |
last |
O(1) | O(1): the last elements are kept apart, in their own array. |
init |
effectively O(1) | effectively O(1): the last array, at most 32 elements, is copied without its last element; the few arrays above it change only when it held one element. |
get |
effectively O(1) | effectively O(1): at most six array reads, whatever the size; one for the first and the last 32 elements. |
update |
effectively O(1) | effectively O(1): the array of 32 elements that holds it is copied, with at most five arrays above it; the rest is shared. |
prepend |
effectively O(1) | effectively O(1): the first array, at most 32 elements, is copied; once every 32 prepends, a few arrays above it are copied too. |
append |
effectively O(1) | effectively O(1): the last array, at most 32 elements, is copied; once every 32 appends, a few arrays above it are copied too. |
prependAll |
O(m) | O(m) for m prepended elements; O(min(n, m)) when iterable is a Vector: the longer side is shared and only the shorter one is copied. O(1) when this Vector is empty and iterable is a Vector, which is returned as is. |
appendAll |
O(m) | O(m) for m appended elements; O(min(n, m)) when iterable is a Vector: the longer side is shared and only the shorter one is copied. O(1) when this Vector is empty and iterable is a Vector, which is returned as is. |
insert |
O(min(i, n - i)) | O(min(i, n - i)): the elements on the shorter side of i are copied, those on the longer side are shared. |
removeAt |
O(min(i, n - i)) | O(min(i, n - i)): the elements on the shorter side of i are copied, those on the longer side are shared. |
take |
effectively O(1) | effectively O(1): the result shares its elements with this Vector; only the few small arrays along the cut are copied. |
drop |
effectively O(1) | effectively O(1): the result shares its elements with this Vector; only the few small arrays along the cut are copied. |
slice |
effectively O(1) | effectively O(1): the result shares its elements with this Vector; only the few small arrays along the cut are copied. |
splitAt(Predicate<? super T>) |
O(k) | O(k) for k elements before the split, then an effectively O(1) split. |
splitAt(int) |
effectively O(1) | effectively O(1): one take and one drop; both parts share their elements with this Vector. |
reverse |
O(n) | O(n). |
sorted |
O(n log n) | O(n log n) comparisons; the elements are copied to an array and sorted there. |
size |
O(1) | O(1): the size is stored. |
sizeCompare(Iterable<?>) |
O(min(n, m)) | O(min(n, m)), at most: a size that is not stored is counted only up to the other one; O(1) when both are stored (Vector, the sets, the maps and the non-empty collections store theirs). A JDK collection is iterated, not asked its size, which may cost a walk or never return. |
sizeCompare(int) |
O(1) | O(1): the stored size is compared. List, Queue and LazyList count their elements up to otherSize + 1. |
contains |
O(n) | O(n): the elements are compared one by one until an equal one is found. The sets and the maps override it with a lookup. |
indexOf |
O(n) | O(n). |
zip |
O(min(n, m)) | O(min(n, m)) for m elements of that. |
sliding(int) |
O(n) | O(n): one effectively O(1) slice per window; each window shares its elements with this Vector, so no element is copied. |
sliding(int, int) |
O(n / step) | O(n / step): one effectively O(1) slice per window; each window shares its elements with this Vector, so no element is copied. |
grouped |
O(n / size) | O(n / size): one effectively O(1) slice per block; each block shares its elements with this Vector. |
distinct |
O(n) | O(n). |
Every method: complexity page.
Sharp edges¶
sliding,groupedandcrossProductreturn aVector, built at once, not an iterator. Each window shares its elements with the originalVector.insertandremoveAtin the middle cost O(min(i, n - i)): the elements on the shorter side are copied.- Building element by element is cheapest through
Vector.Builder, orVector.collector()from ajava.util.stream.Stream.