Docs

Arrays

Growable lists of floats or vectors, local to one run of the expression.

Part of the Wrangle reference. Everything on this page goes in the node's Code field, and runs once per element of the current Run Over mode.

Syntax What it does Example
declare float[] name = expr; / vector[] name = expr; A growable list of floats or vectors, local to this expression. The = is required, same as every other declaration - there is no way to spell "an array with no value yet". An empty one is float[] a = {};. float[] heights = {}; vector[] hits = {}
literal { e1, e2, ... } Build an array from a fixed list of same-typed expressions (all float, or all vector) - up to 256 of them, a compile-time limit naming itself if you cross it. float[] weights = { 1, 0.5, 0.25, 0 }
index (write) a[i] = v; Overwrite element i. Same out-of-range convention as a read: a no-op, counted. Compound forms work too: += -= *= /=. weights[0] = 1; weights[1] += 0.1
vector element swizzle a[i].y Indexing a vector[] yields a vector, which then takes .x/.y/.z (or .r/.g/.b) exactly like any other vector expression. wmap("Weights") = hits[0].y
len(a) Element count, for either array type. for (i = 0; i < len(weights); i += 1) { wmap("Weights") += weights[i] }
append(a, s) / append(a, v) Add one element to the end and return the new length. Mutates a in place - usable as a bare statement, since the length is usually not what you came for. append(weights, 0.75)
insert(a, i, s) / insert(a, i, v) Insert one element at index i (clamped into [0, len(a)]), shifting the rest up; returns the new length. Mutates in place. insert(weights, 0, 1)
removeindex(a, i) Remove the element at index i, shifting the rest down; returns the new length. Out-of-range i is a counted no-op. Mutates in place. removeindex(weights, 0)
resize(a, n) Grow (new elements are zero / the zero vector) or shrink to exactly n elements; returns n. Mutates in place. resize(weights, 8)
find(a, s) / find(a, v) Lowest index whose element exactly equals the value, or -1 if none does. Exact comparison - two floats that came out of arithmetic rarely match exactly, so prefer this for values you set on purpose (ids, flags) over ones you computed. wmap("Weights") = find(weights, 0.5)
sort(a) A fresh float[] with every element in ascending order. Stable - equal elements keep their original relative order, which is what makes chunking a large mesh across worker threads never change the result. Float arrays only. float[] sorted = sort(weights)
argsort(a) A fresh float[] of the indices (as exact whole-number floats) that would put a in ascending order, stable on ties - sort a vector[] (or several parallel arrays) by feeding it a float[] of the key you actually want to sort by. float[] order = argsort(weights)
reverse(a) A fresh array with element order reversed. Works on either array type. float[] r = reverse(weights)
slice(a, lo, hi) A fresh array holding the elements in [lo, hi), clamped into range (a reversed or out-of-range pair just yields fewer elements, never an error). Works on either array type. float[] first3 = slice(weights, 0, 3)
concat(a, b) A fresh array holding every element of a followed by every element of b. Both arguments must be the same array type. float[] all = concat(weights, sort(weights))
sum / avg sum(a) / avg(a) Sum / mean of every element, either array type - a float[] gives a float, a vector[] gives a component-wise vector. avg() of an empty array is 0 (or the zero vector), uncounted: an empty mean has no other honest answer. wmap("Weights") = sum(weights); vector centre = avg(hits)
min / max min(a) / max(a) Smallest / largest element of a float array. A vector[] argument is a compile error naming argsort() + indexing as the fix - there is no single agreed meaning for "the biggest vector". wmap("Weights") = max(weights)

Index (read) - a[i]

The element at index i, 0-based. An out-of-range i (there is no negative indexing - see no negative index below) returns 0 (or the zero vector) and is counted, exactly like every other point-index guard in this language - not an error, so a loop that overshoots by one still finishes and tells you afterward.

wmap("Weights") = weights[0]; vector p = hits[2]

foreach (name in a) { ... }

Iterate any array-typed expression, in index order - name is a fresh local of the array's element type, scoped to the block. The array's handle and length are read once before the loop starts: appending to a from inside the body does not extend the iteration, so a foreach body is always safe to append into a different array from the one it walks.

foreach (h in hits) { wmap("Weights") += h.y }

Value semantics

Assigning an array (float[] b = a; or b = a;) copies it - later writes to b never touch a, and vice versa. A value that is already fresh (a literal, a function's own result) is handed over without copying, since nothing else could be holding onto it yet; passing an array to a function you wrote also copies it into that function's own parameter, for the identical reason.

float[] a = { 1, 2, 3 }; float[] b = a; append(b, 9); wmap("Weights") = len(a)

Per-element lifetime

Every array is scoped to one element's run - vertex, triangle, texel or the single Detail run - and is gone (its slot silently returned to the pool) the moment that element finishes. There is no way to carry an array from one vertex to the next; if you need that, write it into a Weight Map, a User Output or a named attribute instead.

No negative index

a[-1] is not "the last element" - it is an ordinary out-of-range read/write, counted like any other. find() already returns -1 for "not found", and a silently-aliasing negative index would make that -1 look like a hit the moment it was fed straight back into a[]. Use len(a) - 1 to reach the last element on purpose.

wmap("Weights") = weights[len(weights) - 1]

Nearpoints (array) - nearpoints("Pin", p, r)

Every donor vertex id within r of p on the named mesh pin, as a fresh float[], sorted ascending - the value-returning twin of foreach (i in nearpoints("Pin", p, r)) above (see the Donor mesh pins page), for when you want the whole id list rather than to iterate it once. Vertex or Detail run-over.

float[] ids = nearpoints("Donor", P, 5); wmap("Weights") = len(ids)

Guarded growth

An array's total element storage is capped per element - growth past the cap (append/insert/resize/a literal/sort()-and-friends producing a bigger result) is a no-op, counted (ArrayCapacityGuarded) rather than growing without bound. The number of distinct arrays one element may have live at once is capped separately, the same way.