Collections
In the Compute Engine, collections group together multiple elements into one unit. Each element in a collection is a Boxed Expression.
Introduction
The most common types of collection are:
Type | Description | See |
---|---|---|
list | Collection of elements accessible by their index, duplicates allowed | List |
set | Collection of unique elements | Set |
tuple | Collection with a fixed size and optional names | Tuple |
dictionary | Collection of key-value pairs with string keys | Dictionary |
record | Structured data with a fixed set of known string keys |
Collections are immutable: they cannot be modified in place.
Instead, operations on collections produce new collections.
Collections can be used to represent vectors, matrices, sets, mappings, or records — in both finite and infinite forms.
Core Properties of Collections
All collections share these basic properties:
- Elements of the collection can be enumerated
- Elements of the collection can be counted
- Membership of an element can be checked
- Subset relationships with another collection can be checked
Note: Depending on the collection, counting and membership checking can be an expensive operation. See the information on specific collections for details.
In addition, indexed collections support:
- Index-based access: elements can be accessed by their index.
- Finding elements: elements matching a predicate can be found by their index.
Indexed Collections and Non-indexed Collections
Collections fall into two broad categories:
-
Indexed collections, such as
List
andTuple
→ Elements can be accessed by an index, an integer that indicates the position of the element in the collection.
-
Non-indexed collections, such as
Set
andRecord
→ Elements cannot be accessed by index. They can be enumerated or looked up by key.
The first element of an indexed collection has index 1
, the second element
has index 2
, and so on. The last element has index equal to the length of the collection.
Negative indexes can also be used to access elements from the end of the collection, if the collection is finite.
The last element has index -1
, the second to last element has index -2
,
and so on. This is useful for accessing elements without knowing the length of the
collection.
["At", ["List", 2, 5, 7, 11], 3]
// ➔ 7
["At", ["List", 2, 5, 7, 11], -3]
// ➔ 5
Finite and Infinite Collections
Collections may be:
- Finite: containing a definite number of elements
- Infinite: continuing indefinitely (for example, a sequence of all natural numbers)
- Indeterminate: containing an unknown number of elements, such as a stream of data that may end at some point
Compute Engine supports lazy evaluation to make working with infinite collections possible.
Lazy Collections and Eager Collections
Collections can be:
- Eager: elements are fully evaluated when the collection is created.
- Lazy: elements are evaluated only as they are accessed.
Lazy collections are useful when working with with expensive computations and necessary when working with infinite collections.
Some operations like Range
, Cycle
, Iterate
, Repeat
create lazy collections.
Materializing a lazy collection involves evaluating all its elements and storing them in memory, resulting in an eager collection. This is also known as realizing the collection.
To materialize a collection use ListFrom
or SetFrom
. These functions enumerate all elements of a finite
collection and produce a matching eager collection.
["ListFrom", ["Range", 1, 10]]
// ➔ ["List", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Lazy infinite collections provide a natural way to model mathematical sequences, iterative processes, or cyclic patterns, with minimal memory use.
Common examples include:
- Natural numbers (
["Range"]
) - Cyclic patterns (
["Cycle"]
) - Iterative computations (
["Iterate"]
)
For example, let's say you want to express the first 10 prime numbers:
["ListFrom",
["Take",
["Filter", "Integers", ["IsPrime", "_"]],
10
]
]
// ➔ ["List", 2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
In this expression, only the first 10 prime numbers are computed,
and only when the ListFrom
function is called.
Lazy collections are partially materialized when converting an expression to
a string representation, such as when using the expr.latex
, expr.toString()
or expr.print()
methods. A placeholder is inserted to indicate missing
elements.
const expr = ce.box(["Map", "Integers", ["Square", "_"]]);
expr.print();
// ➔ [1, 4, 9, 16, 25...]
Eager Collections
Eager collections are fully materialized when they are created. This means that all elements are computed and stored in memory, making them immediately available for access.
Some of the eager collections include:
-
List: indexed collections of elements, which are also used to represent vectors and matrices. Elements in a list are accessed by their index, which starts at 1. Lists can contain duplicate elements and they can contain an infinite number of elements.
Type:
list<T>
whereT
is the type of the elements. -
Sequence: a sequence is a list but it is handled differently in the Compute Engine. It is used to splice elements into an expression where an element is expected. The
Nothing
symbol is a synonym for the empty sequence. -
Set: non-indexed collections of unique elements. The elements in a set are not accessed by index, they are enumerated. A set can contain an infinite number of elements.
Type:
set<T>
whereT
is the type of the elements. -
Tuple: indexed collections of elements, but with a fixed number of elements that have a specific type and an optional name.
Type:
tuple<T1, T2, ..., Tn>
whereT1
,T2
, ...,Tn
are the types of the elements. -
Dictionary: non-indexed collections of key-value pairs, where each key is unique.
Type: either
dictionary<V>
whereV
is the type of the values, the keys are strings orrecord<K1: T1, K2: T2, ..., Kn: Tn>
whereK1
,K2
, ...,Kn
are the keys andT1
,T2
, ...,Tn
are the types of the values. Thedictionary
type is used when the set of keys is not known in advance, for example when a dictionary is used as a cache. Therecord
type is used when the set of keys is known in advance and fixed, for example to represent a structured data type.
Lazy Collections
Some functions evaluate to a lazy collection. This is useful for creating infinite collections or for collections that are expensive to compute.
Examples of function evaluating to a lazy collection include:
- Range and Linspace: indexed sequences of numbers (integers and reals, respectively) with a specified start, end and step size.
- Cycle: infinite collections that repeat a finite collection.
- Iterate: infinite collections that apply a function to an initial value repeatedly.
- Repeat: infinite collections that repeat a single value.
- Fill: collections of a specified size, where each element is computed by a function or set to a specific value.
Types
- The type
collection
represents any collection, whether indexed or not, finite or infinite. - The type
indexed_collection
applies to collections that support index-based access, such asList
, andTuple
.
Operations on Collections
Operations on all collections, whether indexed or not, include:
- Filter, Map, and Reduce: operations that create new collections by applying a function to each element of an existing collection.
- Length, IsEmpty: check the number of elements of a collection.
- Join, Zip: combine multiple collections into one.
- Tally: count the number of occurrences of each element in a collection.
Operations on indexed collections:
- At, First, Second, Last: access a specific element of a collection.
- Take, Drop, Most, Rest: access a subset of a collection.
- IndexOf: find the index of an element in a collection.
- Extract, Exclude: access a collection of elements at specific indexes.
- Sort, Shuffle, Reverse: reorder a collection.
- Unique: remove duplicates from a collection.
- RotateLeft, RotateRight: rotate a collection to the left or right.
Creating Eager Collections
This section contains functions that create eager collections from some elements.
Sequence(...elements:any) -> collection
A sequence is a collection of elements. When a sequence is used where an element is expected, the elements of the sequence are spliced into the expression.
["List", 1, ["Sequence", 2, 3], 4]
// ➔ ["List", 1, 2, 3, 4]
The Nothing
symbol is a synonym for the empty sequence ["Sequence"]
.
When the Nothing
symbol is used in a context where an element is expected, it is ignored.
["List", 1, "Nothing", 2]
// ➔ ["List", 1, 2]
List(...elements:any) -> list
A List
is an indexed collection of elements. An element in
a list may be repeated.
["List", 42, 3.14, "x", "y"]
The type of a list is list<T>
, where T
is the type of the elements in the list.
The type list
is a shorthand for list<any>
, meaning the list can contain elements of any type.
The visual presentation of a List
expression can be customized using the
Delimiter
function.
const xs = ce.box(["List", 5, 2, 10, 18]);
xs.latex
// ➔ "\lbrack 5, 2, 10, 18 \rbrack"
ce.box(["Delimiter", xs, "<;>"]).latex;
// ➔ "\langle5; 2; 10; 18\rangle"
A vector is represented using a List
of numbers.
["List", 1, 2, 3]
A matrix is represented using a List
of rows of numbers, where each row is
a List
of numbers.
["List",
["List", 1, 2, 3],
["List", 4, 5, 6],
["List", 7, 8, 9]
]
In LaTeX, lists of lists can also be represented using a ;
separator:
And matrices can be represented using LaTeX environments with the \begin{}
and \end{}
commands:
MathJSON | LaTeX |
---|---|
["List", "x", "y", 7, 11] | \lbrack x, y, 7, 11\rbrack |
["List", "x", "Nothing", "y"] | \lbrack x,,y\rbrack |
Set(...elements:any) -> set
A non-indexed collection of unique elements.
["Set", 12, 15, 17]
The type of a set is set<T>
, where T
is the type of the elements in the set.
The type set
is a shorthand for set<any>
, meaning the set can contain elements of any type.
If the same element is repeated, it is included only once in the set. The
elements are compared using the IsSame
function.
["Set", 12, 15, 17, 12, 15]
// ➔ ["Set", 12, 15, 17]
The elements in a set are not ordered. When enumerating a set, the elements are returned in an arbitrary order, and two successive enumerations may return the elements in a different order.
The elements in a set are counted in constant time.
Creating Lazy Collections
Range(upper:integer) -> indexed_collection<integer>
Range(lower:integer, upper:integer) -> indexed_collection<integer>
Range(lower:integer, upper:integer, step:integer) -> indexed_collection<integer>
A sequence of numbers, starting with lower
, ending with upper
, and
incrementing by step
.
If the step
is not specified, it is assumed to be 1.
["Range", 3, 9]
// ➔ ["List", 3, 4, 5, 6, 7, 8, 9]
["Range", 1, 10, 2]
// ➔ ["List", 1, 3, 5, 7, 9]
If there is a single argument, it is assumed to be the upper
bound, and the
lower
bound is assumed to be 1.
["Range", 7]
// ➔ ["List", 1, 2, 3, 4, 5, 6, 7]
If the lower
bound is greater than the upper
bound, the step
must be
negative.
["Range", 10, 1, -1]
// ➔ ["List", 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Linspace(upper:real) -> indexed_collection<real>
Linspace(lower:real, upper:real) -> indexed_collection<real>
Linspace(lower:real, upper:real, count:integer) -> indexed_collection<real>
Linspace
is short for "linearly spaced", from the MATLAB function of the same
name.
A sequence of numbers evenly spaced between lower
and upper
. Similar to Range
but the number of elements in the collection is specified with count
instead of a step
value.
If the count
is not specified, it is assumed to be 50
.
If there is a single argument, it is assumed to be the upper
bound, and the lower
bound is assumed to be 1
.
["Linspace", 3, 10]
// ➔ ["List", 3, 3.142857142857143, 3.2857142857142856,
// 3.4285714285714284, 3.571428571428571, 3.714285714285714,
// 3.857142857142857, 4, 4.142857142857143, 4.285714285714286,
// 4.428571428571429, 4.571428571428571, 4.714285714285714,
// 4.857142857142857, 5, 5.142857142857143, 5.285714285714286,
// 5.428571428571429, 5.571428571428571, 5.714285714285714,
// 5.857142857142857, 6, 6.142857142857143, 6.285714285714286,
// 6.428571428571429, 6.571428571428571, 6.714285714285714,
// 6.857142857142857, 7, 7.142857142857143, 7.285714285714286,
// 7.428571428571429, 7.571428571428571, 7.714285714285714,
// 7.8979591836734695, 8.061224489795919, 8.224489795918368,
// 8.387755102040817, 8.551020408163266, 8.714285714285714,
// 8.877551020408163, 9.040816326530612, 9.204081632653061,
// 9.36734693877551, 9.53061224489796, 9.693877551020408,
// 9.857142857142858, 10]
["Linspace", 2]
// ➔ ["List", 1, 1.1428571428571428, 1.2857142857142858,
// 1.4285714285714286, 1.5714285714285714,
// 1.7142857142857142, 1.8571428571428572, 2]
["Linspace", 1, 10, 5]
// ➔ ["List", 1, 3.25, 5.5, 7.75, 10]
["Linspace", 10, 1, 10]
// ➔ ["List", 10, 9.11111111111111, 8.222222222222221,
// 7.333333333333333, 6.444444444444445,
// 5.555555555555555, 4.666666666666666, 3.7777777777777777,
// 2.888888888888889, 2]
Fill(dimensions, value:any) -> indexed_collection
Fill(dimensions, f:function) -> indexed_collection
Create an indexed collection of the specified dimensions.
If a value
is provided, the elements of the collection are all set to that value.
If a function
is provided, the elements of the collection are computed by applying
the function to the index of the element.
If dimensions
is a number, a collection with that many elements is created.
["Fill", 3, 0]
// ➔ ["List", 0, 0, 0]
If dimension is a tuple, a matrix of the specified dimensions is created.
["Fill", ["Tuple", 2, 3], 0]
// ➔ ["List", ["List", 0, 0, 0], ["List", 0, 0, 0]]
If a function
is specified, it is applied to the index of the element to
compute the value of the element.
["Fill",
["Tuple", 2, 3],
["Function", ["Add", "i", "j"], "i", "j"]
]
// ➔ ["List", ["List", 0, 1, 2], ["List", 1, 2, 3]]
Repeat(value: any) -> indexed_collection
An infinite collection of the same element.
Repeat(value: any, count: integer?) -> indexed_collection
A collection of the same element repeated count
times.
["Repeat", 42, 5]
// ➔ ["List", 42, 42, 42, 42, 42]
Note: ["Repeat", n]
is equivalent to ["Cycle", ["List", n]]
. See
Cycle
for more information.
Cycle(seed:collection) -> indexed_collection
A collection that repeats the elements of the seed
collection. The seed
collection must be finite.
["Cycle", ["List", 5, 7, 2]]
// ➔ ["List", 5, 7, 2, 5, 7, 2, 5, 7, ...]
["Cycle", ["Range", 3]]
// ➔ ["List", 1, 2, 3, 1, 2, 3, 1, 2, ...]
Use Take
to get a finite number of elements.
["Take", ["Cycle", ["List", 5, 7, 2]], 5]
// ➔ ["List", 5, 7, 2, 5, 7]
Iterate(f:function) -> indexed_collection
Iterate(f:function, initial:any) -> indexed_collection
An infinite collection of the results of applying f
to the initial
value.
If the initial
value is not specified, it is assumed to be 0
["Iterate", ["Multiply", "_", 2], 1]
// ➔ ["List", 1, 2, 4, 8, 16, ...]
Use Take
to get a finite number of elements.
["Take", ["Iterate", ["Add", "_", 2]], 7], 5]
// ➔ ["List", 7, 9, 11, 13, 15]
Accessing Elements of Collections
Elements of indexed collections can be accessed using their index.
Indexes start at 1
for the first element. Negative indexes access elements from the end of the collection, with -1
being the last element.
At(xs: indexed_collection, index: integer)
Returns the element at the specified index.
["At", ["List", 5, 2, 10, 18], 2]
// ➔ 10
["At", ["List", 5, 2, 10, 18], -2]
// ➔ 10
At(xs: indexed_collection, ...indexes: integer)
If the collection is nested, the indexes are applied in order.
["At", ["List", ["List", 1, 2], ["List", 3, 4]], 2, 1]
// ➔ 3
First(xs: indexed_collection)
Return the first element of the collection.
["First", ["List", 5, 2, 10, 18]]
// ➔ 5
["First", ["Tuple", "x", "y"]]
// ➔ "x"
It's equivalent to ["At", xs, 1]
.
Second(xs: indexed_collection)
Return the second element of the collection.
["Second", ["Tuple", "x", "y"]]
// ➔ "y"
It's equivalent to ["At", xs, 2]
.
Last(xs: indexed_collection)
Return the last element of the collection.
["Last", ["List", 5, 2, 10, 18]]
// ➔ 18
It's equivalent to ["At", xs, -1]
.
Most(xs: indexed_collection) -> indexed_collection
Return everything but the last element of the collection.
["Most", ["List", 5, 2, 10, 18]]
// ➔ ["List", 5, 2, 10]
It's equivalent to ["Reverse", ["Drop", ["Reverse", xs], 1]]
.
Rest(xs: indexed_collection) -> indexed_collection
Return everything but the first element of the collection.
["Rest", ["List", 5, 2, 10, 18]]
// ➔ ["List", 2, 10, 18]
It's equivalent to ["Drop", xs, 1]
.
Take(xs: indexed_collection, n: integer) -> indexed_collection
Return a list of the first n
elements of xs
. The collection xs
must be indexed.
If n
is negative, it returns the last n
elements.
["Take", ["List", 5, 2, 10, 18], 2]
// ➔ ["List", 5, 2]
["Take", ["List", 5, 2, 10, 18], -2]
// ➔ ["List", 18, 10]
See Drop for a function that returns everything but the first n
elements.
Drop(xs:collection, n:integer) -> collection
Return a list without the first n
elements.
If n
is negative, it returns a list without the last n
elements.
["Drop", ["List", 5, 2, 10, 18], 2]
// ➔ ["List", 10, 18]
["Drop", ["List", 5, 2, 10, 18], -2]
// ➔ ["List", 5, 2]
See Take for a function that returns the first n
elements.
Changing the Order of Elements
Reverse(xs: indexed_collection)
Return the collection in reverse order.
["Reverse", ["List", 5, 2, 10, 18]]
// ➔ ["List", 18, 10, 2, 5]
It's equivalent to ["Extract", xs, ["Tuple", -1, 1]]
.
Extract(xs: indexed_collection, index:integer) -> indexed_collection
Extract(xs: indexed_collection, ...indexes:integer) -> indexed_collection
Extract(xs: indexed_collection, range:tuple<integer, integer>) -> indexed_collection
Returns a list of the elements at the specified indexes.
Extract
always return an indexed collection, even if the result is a single element. If no
elements match, an empty collection is returned.
["Extract", ["List", 5, 2, 10, 18], 2]
// ➔ ["List", 10]
["Extract", ["List", 5, 2, 10, 18], -2, 1]
// ➔ ["List", 10, 5]
["Extract", ["List", 5, 2, 10, 18], 17]
// ➔ ["List"]
When using a range, it is specified as a Tuple
.
// Elements 2 to 3
["Extract", ["List", 5, 2, 10, 18], ["Tuple", 2, 4]]
// ➔ ["List", 2, 10, 18]
// From start to end, every other element
["Extract", ["List", 5, 2, 10, 18], ["Tuple", 1, -1, 2]]
// ➔ ["List", 5, 10]
The elements are returned in the order in which they're specified. Using negative indexes (or ranges) reverses the order of the elements.
// From last to first = reverse
["Extract", ["List", 5, 2, 10, 18], ["Tuple", -1, 1]]
// ➔ ["List", 18, 10, 2, 5]
// From last to first = reverse
["Extract", ""desserts"", ["Tuple", -1, 1]]
// ➔ ""stressed""
An index can be repeated to extract the same element multiple times.
["Extract", ["List", 5, 2, 10, 18], 3, 3, 1]
// ➔ ["List", 10, 10, 5]
Exclude(xs:indexed_collection,, index:integer) -> indexed_collection
Exclude(xs:indexed_collection, indexes:tuple<integer>) -> indexed_collection
Exclude
is the opposite of Extract
. It returns a list of the elements that
are not at the specified indexes.
The order of the elements is preserved.
["Exclude", ["List", 5, 2, 10, 18], 3]
// ➔ ["List", 5, 2, 18]
["Exclude", ["List", 5, 2, 10, 18], -2, 1]
// ➔ ["List", 2, 18]
An index may be repeated, but the corresponding element will only be dropped once.
["Exclude", ["List", 5, 2, 10, 18], 3, 3, 1]
// ➔ ["List", 2, 18]
RotateLeft(xs: indexed_collection, count: integer) -> indexed_collection
Returns a collection where the elements are rotated to the left by the specified count.
["RotateLeft", ["List", 5, 2, 10, 18], 2]
// ➔ ["List", 10, 18, 5, 2]
RotateRight(xs: indexed_collection, count: integer) -> indexed_collection
Returns a collection where the elements are rotated to the right by the specified count.
["RotateRight", ["List", 5, 2, 10, 18], 2]
// ➔ ["List", 10, 18, 5, 2]
Shuffle(xs: indexed_collection) -> indexed_collection
Return the collection in random order.
["Shuffle", ["List", 5, 2, 10, 18]]
// ➔ ["List", 10, 18, 5, 5]
Sort(xs: collection) -> indexed_collection
Sort(xs: collection, order-function: function) -> indexed_collection
Return the collection in sorted order.
["Sort", ["Set", 18, 5, 2, 10]]
// ➔ ["List", 2, 5, 10, 18]
Ordering(collection) -> indexed_collection
Ordering(collection, order-function) -> indexed_collection
Return the indexes of the collection in sorted order.
["Ordering", ["List", 5, 2, 10, 18]]
// ➔ ["List", 2, 1, 3, 4]
To get the values in sorted order, use Extract
:
["Assign", "xs", ["List", 5, 2, 10, 18]]
["Extract", "xs", ["Ordering", "xs"]]
// ➔ ["List", 2, 5, 10, 18]
// Same as Sort:
["Sort", "xs"]
// ➔ ["List", 2, 5, 10, 18]
Operating On Collections
Length(xs: collection) -> integer
Returns the number of elements in the collection.
When the collection is a matrix (list of lists), Length
returns the number of
rows.
["Length", ["List", 5, 2, 10, 18]]
// ➔ 4
IsEmpty(xs: collection) -> boolean
Returns the symbol True
if the collection has no elements.
["IsEmpty", ["List", 5, 2, 10, 18]]
// ➔ "False"
["IsEmpty", ["List"]]
// ➔ "True"
["IsEmpty", "x"]
// ➔ "True"
["IsEmpty", {str: "Hello"}]
// ➔ "False"
Contains(xs: collection, value: any) -> boolean
Returns True
if the collection contains the given value, False
otherwise. The value is compared using the IsSame
function.
["Contains", ["List", 5, 2, 10, 18], 10]
// ➔ "True"
["Contains", ["List", 5, 2, 10, 18], 42]
// ➔ "False"
IndexWhere(xs: indexed_collection, predicate:function) -> number
Returns the 1-based index of the first element in the collection that satisfies the predicate, or 0 if not found.
["IndexWhere", ["List", 5, 2, 10, 18], ["Greater", "_", 9]]
// ➔ 3
Find(xs: indexed_collection, predicate:function)
Returns the first element in the collection that satisfies the predicate, or Nothing
if none found.
["Find", ["List", 5, 2, 10, 18], ["Function", ["Greater", "_", 9]]]
// ➔ 10
["Find", ["List", 5, 2, 10, 18], ["Function", ["Greater", "_", 100]]]
// ➔ "Nothing"
CountIf(xs: indexed_collection, predicate:function) -> number
Returns the number of elements in the collection that satisfy the predicate.
["CountIf", ["List", 5, 2, 10, 18], ["Greater", "_", 5]]
// ➔ 2
Position(collection, predicate:function)
Returns a list of indexes of elements in the collection that satisfy the predicate.
["Position", ["List", 5, 2, 10, 18], ["Function", ["Greater", "_", 5]]]
// ➔ ["List", 3, 4]
Exists(collection, predicate:function)
Returns True
if any element of the collection satisfies the predicate, False
otherwise.
["Exists", ["List", 5, 2, 10, 18], ["Function", ["Greater", "_", 15]]]
// ➔ "True"
["Exists", ["List", 5, 2, 10], ["Function", ["Greater", "_", 15]]]
// ➔ "False"
ForAll(collection, predicate:function)
Returns True
if all elements of the collection satisfy the predicate, False
otherwise.
["ForAll", ["List", 5, 2, 10, 18], ["Function", ["Greater", "_", 0]]]
// ➔ "True"
["ForAll", ["List", 5, 2, 10, 18], ["Function", ["Greater", "_", 5]]]
// ➔ "False"
Filter(xs: collection, pred: function) -> collection
Returns a collection where pred is applied to each element of the
collection. Only the elements for which the predicate returns "True"
are kept.
["Filter", ["List", 5, 2, 10, 18], ["Function", ["Less", "_", 10]]]
// ➔ ["List", 5, 2]
Map(xs:collection, f:function) -> collection
Returns a collection where f is applied to each element of xs.
["Map", ["List", 5, 2, 10, 18], ["Function", ["Add", "x", 1], "x"]]
// ➔ ["List", 6, 3, 11, 19]
["Map", ["List", 5, 2, 10, 18], ["Multiply", "_", 2]]
// ➔ ["List", 10, 4, 20, 36]
Reduce(xs:indexed_collection, fn:function, initial:value?) -> value
Returns a value by applying the reducing function fn to each element of the collection.
Reduce
performs a left fold operation: the reducing function is applied to the
first two elements, then to the result of the previous application and the next
element, etc...
When an initial
value is provided, the reducing function is applied to the
initial value and the first element of the collection, then to the result of the
previous application and the next element, etc...
[
"Reduce",
["List", 5, 2, 10, 18],
["Function", ["Add", "_1", "_2"]],
]
// ➔ 35
The name of a function can be used as a shorthand for a function that takes two arguments.
["Reduce", ["List", 5, 2, 10, 18], "Add"]
// ➔ 35
Tally(xs:collection) -> tuple<elements:list, counts:list>
Evaluate to a tuple of two lists:
- The first list contains the unique elements of the collection.
- The second list contains the number of times each element appears in the collection.
["Tally", ["List", 5, 2, 10, 18, 5, 2, 5]]
// ➔ ["Tuple", ["List", 5, 2, 10, 18], ["List", 3, 2, 1, 1]]
Zip(...xss: indexed_collection)
Returns a collection of tuples where the first element of each tuple is the first element of the first collection, the second element of each tuple is the second element of the second collection, etc.
The length of the resulting collection is the length of the shortest collection.
["Zip", ["List", 1, 2, 3], ["List", 4, 5, 6]]
// ➔ ["List", ["Tuple", 1, 4], ["Tuple", 2, 5], ["Tuple", 3, 6]]
Partition(collection, count:integer)
Partition(collection, predicate:function)
Partitions a collection into groups. If an integer is given, splits into that many groups. If a predicate function is given, splits into two groups: elements for which the predicate is true, and those for which it is false.
["Partition", ["List", 1, 2, 3, 4, 5, 6], 2]
// ➔ ["List", ["List", 1, 2, 3], ["List", 4, 5, 6]]
["Partition", ["List", 1, 2, 3, 4, 5, 6], ["Function", ["Even", "_"]]]
// ➔ ["List", ["List", 2, 4, 6], ["List", 1, 3, 5]]
Chunk(collection, count:integer)
Splits the collection into count
nearly equal-sized chunks.
["Chunk", ["List", 1, 2, 3, 4, 5], 2]
// ➔ ["List", ["List", 1, 2, 3], ["List", 4, 5]]
GroupBy(collection, function:function)
Partitions the collection into groups according to the value of the grouping function applied to each element. Returns a dictionary mapping group keys to lists of elements.
["GroupBy", ["List", 1, 2, 3, 4], ["Function", ["Even", "_"]]]
// ➔ ["Dictionary", ["Tuple", "True", ["List", 2, 4]], ["Tuple", "False", ["List", 1, 3]]]
Transforming Collections
This section contains functions whose argument is a collection and which return a collection made of a subset of the elements of the input.
Collections are immutable. These functions do not modify the input collection, but return a new collection.
Join(...collection) -> list
Join(...set) -> set
If the collections are of different types, the result is a List
containing the elements of the first collection followed
by the elements of the second collection.
["Join", ["List", 5, 2, 10, 18], ["List", 1, 2, 3]]
// ➔ ["List", 5, 2, 10, 18, 1, 2, 3]
If the collections are all sets , the result is a Set
of the
elements of the collections.
["Join", ["Set", 5, 2, 10, 18], ["Set", 1, 2, 3]]
// ➔ ["Set", 5, 2, 10, 18, 1, 3]
Unique(xs: collection) -> collection
Returns a list of the elements in xs
without duplicates.
This is equivalent to the first element of the result of Tally
:
["First", ["Tally", xs]]
.
["Unique", ["List", 5, 2, 10, 18, 5, 2, 5]]
// ➔ ["List", 5, 2, 10, 18]
Materializing Collections
Materializing a collection means converting it from a lazy representation to an eager one. This involves evaluating all elements of the collection and storing them in memory.
ListFrom(xs: collection) -> list
SetFrom(xs: collection) -> set
TupleFrom(xs: collection) -> tuple
Returns a materialized list, set or tuple containing the elements of the
collection xs
.
The collection xs
should be a finite collection.
["ListFrom", ["Range", 1, 3]]
// ➔ ["List", 1, 2, 3]
["SetFrom", ["Range", 1, 3]]
// ➔ ["Set", 1, 2, 3]
["TupleFrom", ["Range", 1, 3]]
// ➔ ["Tuple", 1, 2, 3]
RecordFrom(xs: collection) -> record
DictionaryFrom(xs: collection) -> map
Returns a record or map containing the elements of the collection xs
.
The collection xs
should be a finite collection of key-value pairs, each key being
a string.
["RecordFrom", ["List", ["Tuple", "'a'", 1], ["Tuple", "'b'", 2]]]
// ➔ ["Record", ["Tuple", "'a'", 1], ["Tuple", "'b'", 2]]
["DictionaryFrom", ["List", ["Tuple", "'a'", 1], ["Tuple", "'b'", 2]]]
// ➔ ["Dictionary", ["Tuple", "'a'", 1], ["Tuple", "'b'", 2]]