List¶
The List
type has the following methods.
all¶
List.all: (self: List[T], predicate: T -> Bool) -> Bool
Return whether the predicate is true for all elements in the list. For example:
// Evaluates to true.
[11, 17, 42].all(x => x > 0)
// Evaluates to false.
[11, 17, 42].all(x => x > 20)
// Evaluates to true.
[].all(x => false)
This method short-circuits: when the outcome is decided, it will not call the predicate for the remaining elements in the list.
any¶
List.any: (self: List[T], predicate: T -> Bool) -> Bool
Return whether the predicate is true for any element in the list. For example:
// Evaluates to true.
[11, 17, 42].any(x => x > 17)
// Evaluates to false.
[11, 17, 42].any(x => x > 42)
// Evaluates to false.
[].any(x => true)
This method short-circuits: when the outcome is decided, it will not call the predicate for the remaining elements in the list.
contains¶
List.contains: (self: List[T], element: T) -> Bool
Return whether the list contains a given element. For example:
[for needle in ["a", "z"]: ["a", "b", "c"].contains(needle)]
// Evaluates to:
[true, false]
enumerate¶
List.enumerate: (self: List[T]) -> Dict[Int, T]
Return a mapping from index to list element. The index is zero-based.
["x", "y", "z"].enumerate()
// Evaluates to:
{ 0: "x", 1: "y", 2: "z" }
This is mostly useful for iterating:
let pieces = ["pawn", "queen", "bisshop"];
let unordered_pairs = [
for i, piece_i in pieces.enumerate():
for j in std.range(i + 1, pieces.len()):
let piece_j = pieces[j];
[piece_i, piece_j]
];
unordered_pairs
// Evaluates to:
[["pawn", "queen"], ["pawn", "bisshop"], ["queen", "bisshop"]]
filter¶
List.filter: (self: List[T], predicate: T -> Bool) -> List[T]
Construct a new list that contains only the elements where predicate
returned true. The result is equivalent to a list comprehension, a
and b
are identical in this example:
let xs = [1, 2, 3];
let a = xs.filter(x => x > 1);
let b = [
for x in xs:
if x > 1:
x
];
// Both a and b evaluate to:
[2, 3]
List comprehensions are more general than filter
: they support nested loops, and let-bindings are accessible to the inner scope. Still, filter
can be useful, especially for iteratively refining a query in an rcl query
command.
flat_map¶
List.flat_map: (self: List[T], map_element: T -> List[U]) -> List[U]
Construct a new list by taking every element in the list, applying map_element
to it (which should return a collection), and concatenating those results. flat_map
is like map
, except that it flattens the result. It is equivalent to a list comprehension with a nested loop: a
and b
are identical in this example:
let apps = [
{ name = "sshd", ports = [22] },
{ name = "nginx", ports = [80, 443] },
];
let a = apps.flat_map(app => app.ports);
let b = [
for app in apps:
for port in app.ports:
port
];
// Both a and b evaluate to:
[22, 80, 443]
List comprehensions are often clearer in configuration files, especially when the body is large. They are also more general: list comprehensions support arbitrary nesting, filtering with if
, and let-bindings are accessible to the inner scope. Still, flat_map
can be useful, especially for iteratively refining a query in an rcl query
command.
fold¶
List.fold: (self: List[T], seed: U, reduce: (U, T) -> U) -> U
Left-fold the function reduce
over the list, with seed
as the initial accumulator value.
[2, 3, 5, 7, 11].fold(
{ min = 99, max = 0 },
(acc, x) => {
min = if acc.min < x: acc.min else: x,
max = if acc.max > x: acc.max else: x,
},
)
// Evaluates to:
{ max = 11, min = 2 }
group_by¶
List.group_by: (self: List[T], get_key: T -> U) -> Dict[U, List[T]]
Group the elements of the list by a key selected by get_key
. Within groups, the original order of elements is preserved.
let foods = [
{ category = "fruit", name = "apple" },
{ category = "fruit", name = "pear" },
{ category = "vegetable", name = "onion" },
{ category = "vegetable", name = "carrot" },
];
foods.group_by(food => food.category)
// Evaluates to:
{
fruit = [
{ category = "fruit", name = "apple" },
{ category = "fruit", name = "pear" },
],
vegetable = [
{ category = "vegetable", name = "onion" },
{ category = "vegetable", name = "carrot" },
],
}
join¶
List.join: (self: List[T], separator: String) -> String
Concatenate the elements with the separator in between. This is equivalent to using a format string, therefore the list elements must be string formattable.
// Evaluates to "foo-bar".
["foo", "bar"].join("-")
// Evaluates to "2,3,5".
[2, 3, 5].join(",")
// Error, dicts are not string formattable.
[{}, {}].join("")
key_by¶
List.key_by: (self: List[T], get_key: T -> U) -> Dict[U, T]
Build a dictionary with the key selected by get_key
as key, and the list elements as values. The keys must be unique. When a key is not unique, this method fails and reports the conflicting values.
let replicants = [
{ name = "rachael", generation = 7 },
{ name = "rbatty", generation = 6 },
{ name = "zsalome", generation = 6 },
];
replicants.key_by(r => r.name)
// Evaluates to:
{
rachael = { name = "rachael", generation = 7 },
rbatty = { name = "rbatty", generation = 6 },
zsalome = { name = "zsalome", generation = 6 },
}
replicants.key_by(r => r.generation)
// This fails with the following error:
// Error: The key 6 is not unique. The following values use this key:
// { generation = 6, name = "rbatty" }
// { generation = 6, name = "zsalome" }
len¶
List.len: (self: List[T]) -> Int
Return the number of elements in the list. For example:
// Evaluates to 3.
[1, 2, 3].len()
map¶
List.map: (self: List[T], map_element: T -> U) -> List[U]
Construct a new list by applying map_element
to every element in the list. The result is equivalent to a list comprehension, a
and b
are identical in this example:
let xs = [1, 2, 3];
let a = [for x in xs: x * 2];
let b = xs.map(x => x * 2);
// Both a and b evaluate to:
[2, 4, 6]
List comprehensions are often clearer in configuration files, especially when the body is large. They are also more general: list comprehensions support nested loops and filtering with if
. Still, map
can be useful, especially for iteratively refining a query in an rcl query
command.
reverse¶
List.reverse: (self: List[T]) -> List[T]
Return the list in reverse.
[1, 2, 3].reverse()
// Evaluates to:
[3, 2, 1]
sort¶
List.sort: (self: List[T]) -> List[T]
Return a sorted version of the list. Elements of the same type will be sorted with respect to each other. The relative order of elements of different types is an implementation detail that may change between versions.
[11, 5, 7].sort()
// Evaluates to:
[5, 7, 11]
sum¶
List.sum: (self: List[Int]) -> Int
Return the sum of the elements in the list. For example:
// Evaluates to 42.
[3, 7, 11, 21].sum()