This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/rhai_engine/rhaibook/language/arrays.md
2025-04-03 09:18:05 +02:00

29 KiB
Raw Blame History

Arrays

{{#include ../links.md}}


Always limit the [maximum size of arrays].

Arrays are first-class citizens in Rhai.

All elements stored in an array are [Dynamic], and the array can freely grow or shrink with elements added or removed.

The Rust type of a Rhai array is rhai::Array which is an alias to Vec<Dynamic>.

[type_of()] an array returns "array".

Arrays are disabled via the [no_index] feature.

Literal Syntax

Array literals are built within square brackets [ ... ] and separated by commas ,:

[ value, value, ... , value ]

[ value, value, ... , value , ] // trailing comma is OK

Element Access Syntax

From beginning

Like C, arrays are accessed with zero-based, non-negative integer indices:

array [ index position from 0 to (length1) ]

From end

A negative position accesses an element in the array counting from the end, with 1 being the last element.

array [ index position from 1 to length ]

Out-of-Bounds Index

Trying to read from an index that is out of bounds causes an error.


For fine-tuned control on what happens when an out-of-bounds index is accessed,
see [_Out-of-Bounds Index for Arrays_](arrays-oob.md).

Built-in Functions

The following methods (mostly defined in the [BasicArrayPackage][built-in packages] but excluded when using a [raw Engine]) operate on arrays.

Function Parameter(s) Description
get position, counting from end if < 0 gets a copy of the element at a certain position ([()] if the position is not valid)
set
  1. position, counting from end if < 0
  2. new element
sets a certain position to a new value (no effect if the position is not valid)
push, += operator element to append (not an array) appends an element to the end
append, += operator array to append concatenates the second array to the end of the first
+ operator
  1. first array
  2. second array
concatenates the first array with the second
== operator
  1. first array
  2. second array
are two arrays the same (elements compared with the == operator, if defined)?
!= operator
  1. first array
  2. second array
are two arrays different (elements compared with the == operator, if defined)?
insert
  1. position, counting from end if < 0, end if ≥ length
  2. element to insert
inserts an element at a certain position
pop none removes the last element and returns it ([()] if empty)
shift none removes the first element and returns it ([()] if empty)
extract
  1. start position, counting from end if < 0, end if ≥ length
  2. (optional) number of elements to extract, none if ≤ 0, to end if omitted
extracts a portion of the array into a new array
extract [range] of elements to extract, from beginning if ≤ 0, to end if ≥ length extracts a portion of the array into a new array
remove position, counting from end if < 0 removes an element at a particular position and returns it ([()] if the position is not valid)
reverse none reverses the array
len method and property none returns the number of elements
is_empty method and property none returns true if the array is empty
pad
  1. target length
  2. element to pad
pads the array with an element to at least a specified length
clear none empties the array
truncate target length cuts off the array at exactly a specified length (discarding all subsequent elements)
chop target length cuts off the head of the array, leaving the tail at exactly a specified length
split
  1. array
  2. position to split at, counting from end if < 0, end if ≥ length
splits the array into two arrays, starting from a specified position
for_each [function pointer] for processing elements run through each element in the array in order, binding each to this and calling the processing function taking the following parameters:
  1. this: array element
  2. (optional) index position
drain [function pointer] to predicate (usually a [closure]) removes all elements (returning them) that return true when called with the predicate function taking the following parameters (if none, the array element is bound to this):
  1. array element
  2. (optional) index position
drain
  1. start position, counting from end if < 0, end if ≥ length
  2. number of elements to remove, none if ≤ 0
removes a portion of the array, returning the removed elements as a new array
drain [range] of elements to remove, from beginning if ≤ 0, to end if ≥ length removes a portion of the array, returning the removed elements as a new array
retain [function pointer] to predicate (usually a [closure]) removes all elements (returning them) that do not return true when called with the predicate function taking the following parameters (if none, the array element is bound to this):
  1. array element
  2. (optional) index position
retain
  1. start position, counting from end if < 0, end if ≥ length
  2. number of elements to retain, none if ≤ 0
retains a portion of the array, removes all other elements and returning them as a new array
retain [range] of elements to retain, from beginning if ≤ 0, to end if ≥ length retains a portion of the array, removes all other bytes and returning them as a new array
splice
  1. start position, counting from end if < 0, end if ≥ length
  2. number of elements to remove, none if ≤ 0
  3. array to insert
replaces a portion of the array with another (not necessarily of the same length as the replaced portion)
splice
  1. [range] of elements to remove, from beginning if ≤ 0, to end if ≥ length
  2. array to insert
replaces a portion of the array with another (not necessarily of the same length as the replaced portion)
filter [function pointer] to predicate (usually a [closure]) constructs a new array with all elements that return true when called with the predicate function taking the following parameters (if none, the array element is bound to this):
  1. array element
  2. (optional) index position
contains, [in] operator element to find does the array contain an element? The == operator (if defined) is used to compare [custom types]
index_of
  1. element to find (not a [function pointer])
  2. (optional) start position, counting from end if < 0, end if ≥ length
returns the position of the first element in the array that equals the supplied element (using the == operator, if defined), or 1 if not found
index_of
  1. [function pointer] to predicate (usually a [closure])
  2. (optional) start position, counting from end if < 0, end if ≥ length
returns the position of the first element in the array that returns true when called with the predicate function, or 1 if not found:
  1. array element (if none, the array element is bound to this)
  2. (optional) index position
find
  1. [function pointer] to predicate (usually a [closure])
  2. (optional) start position, counting from end if < 0, end if ≥ length
returns the first element in the array that returns true when called with the predicate function, or [()] if not found:
  1. array element (if none, the array element is bound to this)
  2. (optional) index position
find_map
  1. [function pointer] to predicate (usually a [closure])
  2. (optional) start position, counting from end if < 0, end if ≥ length
returns the first non-[()] value of the first element in the array when called with the predicate function, or [()] if not found:
  1. array element (if none, the array element is bound to this)
  2. (optional) index position
dedup (optional) [function pointer] to predicate (usually a [closure]); if omitted, the == operator is used, if defined removes all but the first of consecutive elements in the array that return true when called with the predicate function (non-consecutive duplicates are not removed):
1st & 2nd parameters: two elements in the array
map [function pointer] to conversion function (usually a [closure]) constructs a new array with all elements mapped to the result of applying the conversion function taking the following parameters (if none, the array element is bound to this):
  1. array element
  2. (optional) index position
reduce
  1. [function pointer] to accumulator function (usually a [closure])
  2. (optional) the initial value
reduces the array into a single value via the accumulator function taking the following parameters (if the second parameter is omitted, the array element is bound to this):
  1. accumulated value ([()] initially)
  2. this: array element
  3. (optional) index position
reduce_rev
  1. [function pointer] to accumulator function (usually a [closure])
  2. (optional) the initial value
reduces the array (in reverse order) into a single value via the accumulator function taking the following parameters (if the second parameter is omitted, the array element is bound to this):
  1. accumulated value ([()] initially)
  2. this: array element
  3. (optional) index position
zip
  1. array to zip
  2. [function pointer] to conversion function (usually a [closure])
constructs a new array with all element pairs from two arrays mapped to the result of applying the conversion function taking the following parameters:
  1. first array element
  2. second array element
  3. (optional) index position
some [function pointer] to predicate (usually a [closure]) returns true if any element returns true when called with the predicate function taking the following parameters (if none, the array element is bound to this):
  1. array element
  2. (optional) index position
all [function pointer] to predicate (usually a [closure]) returns true if all elements return true when called with the predicate function taking the following parameters (if none, the array element is bound to this):
  1. array element
  2. (optional) index position
sort [function pointer] to a comparison function (usually a [closure]) sorts the array with a comparison function taking the following parameters:
  1. first element
  2. second element
    return value: INT < 0 if first < second, > 0 if first > second, 0 if first == second
sort none sorts a homogeneous array containing only elements of the same comparable built-in type (INT, FLOAT, [Decimal][rust_decimal], [string], [character], bool, [()])

To use a [custom type] with arrays, a number of functions need to be manually implemented,
in particular the `==` operator in order to support the [`in`] operator which uses `==` (via the
`contains` method) to compare elements.

See the section on [custom types] for more details.

Examples

let y = [2, 3];             // y == [2, 3]

let y = [2, 3,];            // y == [2, 3]

y.insert(0, 1);             // y == [1, 2, 3]

y.insert(999, 4);           // y == [1, 2, 3, 4]

y.len == 4;

y[0] == 1;
y[1] == 2;
y[2] == 3;
y[3] == 4;

(1 in y) == true;           // use 'in' to test if an element exists in the array

(42 in y) == false;         // 'in' uses the 'contains' function, which uses the
                            // '==' operator (that users can override)
                            // to check if the target element exists in the array

y.contains(1) == true;      // the above de-sugars to this

y[1] = 42;                  // y == [1, 42, 3, 4]

(42 in y) == true;

y.remove(2) == 3;           // y == [1, 42, 4]

y.len == 3;

y[2] == 4;                  // elements after the removed element are shifted

ts.list = y;                // arrays can be assigned completely (by value copy)

ts.list[1] == 42;

[1, 2, 3][0] == 1;          // indexing on array literal

[1, 2, 3][-1] == 3;         // negative position counts from the end

fn abc() {
    [42, 43, 44]            // a function returning an array
}

abc()[0] == 42;

y.push(4);                  // y == [1, 42, 4, 4]

y += 5;                     // y == [1, 42, 4, 4, 5]

y.len == 5;

y.shift() == 1;             // y == [42, 4, 4, 5]

y.chop(3);                  // y == [4, 4, 5]

y.len == 3;

y.pop() == 5;               // y == [4, 4]

y.len == 2;

for element in y {          // arrays can be iterated with a 'for' statement
    print(element);
}

y.pad(6, "hello");          // y == [4, 4, "hello", "hello", "hello", "hello"]

y.len == 6;

y.truncate(4);              // y == [4, 4, "hello", "hello"]

y.len == 4;

y.clear();                  // y == []

y.len == 0;

// The examples below use 'a' as the master array

let a = [42, 123, 99];

a.for_each(|| this *= 2);

a == [84, 246, 198];

a.for_each(|i| this /= 2);

a == [42, 123, 99];

a.map(|v| v + 1);           // returns [43, 124, 100]

a.map(|| this + 1);         // returns [43, 124, 100]

a.map(|v, i| v + i);        // returns [42, 124, 101]

a.filter(|v| v > 50);       // returns [123, 99]

a.filter(|| this > 50);     // returns [123, 99]

a.filter(|v, i| i == 1);    // returns [123]

a.filter("is_odd");         // returns [123, 99]

a.filter(Fn("is_odd"));     // <- previous statement is equivalent to this...

a.filter(|v| is_odd(v));    // <- or this

a.some(|v| v > 50);         // returns true

a.some(|| this > 50);       // returns true

a.some(|v, i| v < i);       // returns false

a.all(|v| v > 50);          // returns false

a.all(|| this > 50);        // returns false

a.all(|v, i| v > i);        // returns true

// Reducing - initial value provided directly
a.reduce(|sum| sum + this, 0) == 264;

// Reducing - initial value provided directly
a.reduce(|sum, v| sum + v, 0) == 264;

// Reducing - initial value is '()'
a.reduce(
    |sum, v| if sum.type_of() == "()" { v } else { sum + v }
) == 264;

// Reducing - initial value has index position == 0
a.reduce(|sum, v, i|
    if i == 0 { v } else { sum + v }
) == 264;

// Reducing in reverse - initial value provided directly
a.reduce_rev(|sum| sum + this, 0) == 264;

// Reducing in reverse - initial value provided directly
a.reduce_rev(|sum, v| sum + v, 0) == 264;

// Reducing in reverse - initial value is '()'
a.reduce_rev(
    |sum, v| if sum.type_of() == "()" { v } else { sum + v }
) == 264;

// Reducing in reverse - initial value has index position == 0
a.reduce_rev(|sum, v, i|
    if i == 2 { v } else { sum + v }
) == 264;

// In-place modification

a.splice(1..=1, [1, 3, 2]); // a == [42, 1, 3, 2, 99]

a.extract(1..=3);           // returns [1, 3, 2]

a.sort(|x, y| y - x);       // a == [99, 42, 3, 2, 1]

a.sort();                   // a == [1, 2, 3, 42, 99]

a.drain(|v| v <= 1);        // a == [2, 3, 42, 99]

a.drain(|v, i| i  3);      // a == [2, 3, 42]

a.retain(|v| v > 10);       // a == [42]

a.retain(|v, i| i > 0);     // a == []