242 lines
11 KiB
Markdown
242 lines
11 KiB
Markdown
# Lists, Maps and API support for Containers
|
|
|
|
Scarpet supports basic container types: lists and maps (aka hashmaps, dicts etc..)
|
|
|
|
## Container manipulation
|
|
|
|
Here is a list of operations that work on all types of containers: lists, maps, as well as other Minecraft specific
|
|
modifyable containers, like NBTs
|
|
|
|
### `get(container, address, ...), get(lvalue), ':' operator`
|
|
|
|
Returns the value at `address` element from the `value`. For lists it indicates an index, use negative numbers to
|
|
reach elements from the end of the list. `get` call will always be able to find the index. In case there is few
|
|
items, it will loop over
|
|
|
|
for maps, retrieves the value under the key specified in the `address` or null otherwise
|
|
|
|
[Minecraft specific usecase]: In case `value` is of `nbt` type, uses address as the nbt path to query, returning null,
|
|
if path is not found, one value if there was one match, or list of values if result is a list. Returned elements can
|
|
be of numerical type, string texts, or another compound nbt tags
|
|
|
|
In case to simplify the access with nested objects, you can add chain of addresses to the arguments of `get` rather
|
|
than calling it multiple times. `get(get(foo,a),b)` is equivalent to `get(foo, a, b)`, or `foo:a:b`.
|
|
|
|
<pre>
|
|
get(l(range(10)), 5) => 5
|
|
get(l(range(10)), -1) => 9
|
|
get(l(range(10)), 10) => 0
|
|
l(range(10)):93 => 3
|
|
get(player() ~ 'nbt', 'Health') => 20 // inefficient way to get player health, use player() ~ 'health' instead
|
|
get(m( l('foo',2), l('bar',3), l('baz',4) ), 'bar') => 3
|
|
</pre>
|
|
|
|
### `has(container, address, ...), has(lvalue)`
|
|
|
|
Similar to `get`, but returns boolean value indicating if the given index / key / path is in the container.
|
|
Can be used to determine if `get(...)==null` means the element doesn't exist, or the stored value for this
|
|
address is `null`, and is cheaper to run than `get`.
|
|
|
|
Like get, it can accept multiple addresses for chains in nested containers. In this case `has(foo:a:b)` is
|
|
equivalent to `has(get(foo,a), b)` or `has(foo, a, b)`
|
|
|
|
### `delete(container, address, ...), delete(lvalue)`
|
|
|
|
Removes specific entry from the container. For the lists - removes the element and shrinks it. For maps, it
|
|
removes the key from the map, and for nbt - removes content from a given path. For lists and maps returns previous
|
|
entry at the address, for nbt's - number of removed objects, with 0 indicating that the original value was unaffected.
|
|
|
|
Like with the `get` and `has`, `delete` can accept chained addresses, as well as l-value container access, removing
|
|
the value from the leaf of the path provided, so `delete(foo, a, b)` is the
|
|
same as `delete(get(foo,a),b)` or `delete(foo:a:b)`
|
|
|
|
Returns true, if container was changed, false, if it was left unchanged, and null if operation was invalid.
|
|
|
|
### `put(container, address, value), put(container, address, value, mode), put(lvalue, value)`
|
|
|
|
<u>**Lists**</u>
|
|
|
|
Modifies the container by replacing the value under the address with the supplied `value`. For lists, a valid
|
|
index is required, but can be negative as well to indicate positions from the end of the list. If `null` is
|
|
supplied as the address, it always means - add to the end of the list.
|
|
|
|
There are three modes that lists can have items added to them:
|
|
|
|
* `replace`(default): Replaces item under given index(address). Doesn't change the size of the array
|
|
unless `null` address is used, which is an exception and then it appends to the end
|
|
* `insert`: Inserts given element at a specified index, shifting the rest of the array to make space for the item.
|
|
Note that index of -1 points to the last element of the list, thus inserting at that position and moving the previous
|
|
last element to the new last element position. To insert at the end, use `+=` operator, or `null` address in put
|
|
* `extend`: treats the supplied value as an iterable set of values to insert at a given index, extending the list
|
|
by this amount of items. Again use `null` address/index to point to the end of the list
|
|
|
|
Due to the extra mode parameter, there is no chaining for `put`, but you can still use l-value container access to
|
|
indicate container and address, so `put(foo, key, value)` is the same as `put(foo:key, value)` or `foo:key=value`
|
|
|
|
Returns true, if container got modified, false otherwise, and null if operation was invalid.
|
|
|
|
<u>**Maps**</u>
|
|
|
|
For maps there are no modes available (yet, seems there is no reason to). It replaces the value under the supplied
|
|
key (address), or sets it if not currently present.
|
|
|
|
<u>**NBT Tags**</u>
|
|
|
|
The address for nbt values is a valid nbt path that you would use with `/data` command, and tag is any tag that
|
|
would be applicable for a given insert operation. Note that to distinguish between proper types (like integer types,
|
|
you need to use command notation, i.e. regular ints is `123`, while byte size int would be `123b` and an explicit
|
|
string would be `"5"`, so it helps that scarpet uses single quotes in his strings. Unlike for lists and maps, it
|
|
returns the number of affected nodes, or 0 if none were affected.
|
|
|
|
There are three modes that NBT tags can have items added to them:
|
|
|
|
* `replace`(default): Replaces item under given path(address). Removes them first if possible, and then adds given
|
|
element to the supplied position. The target path can indicate compound tag keys, lists, or individual elements
|
|
of the lists.
|
|
* `<N>`: Index for list insertions. Inserts given element at a specified index, inside a list specified with the
|
|
path address. Fails if list is not specified. It behaves like `insert` mode for lists, i.e. it is not removing any
|
|
of the existing elements. Use `replace` to remove and replace existing element.
|
|
* `merge`: assumes that both path and replacement target are of compound type (dictionaries, maps, `{}` types),
|
|
and merges keys from `value` with the compound tag under the path
|
|
|
|
<pre>
|
|
a = l(1, 2, 3); put(a, 1, 4); a => [1, 4, 3]
|
|
a = l(1, 2, 3); put(a, null, 4); a => [1, 2, 3, 4]
|
|
a = l(1, 2, 3); put(a, 1, 4, 'insert'); a => [1, 4, 2, 3]
|
|
a = l(1, 2, 3); put(a, null, l(4, 5, 6), 'extend'); a => [1, 2, 3, 4, 5, 6]
|
|
a = l(1, 2, 3); put(a, 1, l(4, 5, 6), 'extend'); a => [1, 4, 5, 6, 2, 3]
|
|
a = l(l(0,0,0),l(0,0,0),l(0,0,0)); put(a.1, 1, 1); a => [[0, 0, 0], [0, 1, 0], [0, 0, 0]]
|
|
a = m(1,2,3,4); put(a, 5, null); a => {1: null, 2: null, 3: null, 4: null, 5: null}
|
|
tag = nbt('{}'); put(tag, 'BlockData.Properties', '[1,2,3,4]'); tag => {BlockData:{Properties:[1,2,3,4]}}
|
|
tag = nbt('{a:[{lvl:3},{lvl:5},{lvl:2}]}'); put(tag, 'a[].lvl', 1); tag => {a:[{lvl:1},{lvl:1},{lvl:1}]}
|
|
tag = nbt('{a:[{lvl:[1,2,3]},{lvl:[3,2,1]},{lvl:[4,5,6]}]}'); put(tag, 'a[].lvl', 1, 2); tag
|
|
=> {a:[{lvl:[1,2,1,3]},{lvl:[3,2,1,1]},{lvl:[4,5,1,6]}]}
|
|
tag = nbt('{a:[{lvl:[1,2,3]},{lvl:[3,2,1]},{lvl:[4,5,6]}]}'); put(tag, 'a[].lvl[1]', 1); tag
|
|
=> {a:[{lvl:[1,1,3]},{lvl:[3,1,1]},{lvl:[4,1,6]}]}
|
|
</pre>
|
|
|
|
## List operations
|
|
|
|
### `l(values ...), l(iterator)`
|
|
|
|
Creates a list of values of the expressions passed as parameters. It can be used as an L-value and if all
|
|
elements are variables, you coujld use it to return multiple results from one function call, if that
|
|
function returns a list of results with the same size as the `l` call uses. In case there is only one
|
|
argument and it is an iterator (vanilla expression specification has `range`, but Minecraft API implements
|
|
a bunch of them, like `diamond`), it will convert it to a proper list. Iterators can only be used in high order
|
|
functions, and are treated as empty lists, unless unrolled with `l`
|
|
|
|
<pre>
|
|
l(1,2,'foo') => [1, 2, foo]
|
|
l() => [] (empty list)
|
|
l(range(10)) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
l(1, 2) = l(3, 4) => Error: l is not a variable
|
|
l(foo, bar) = l(3,4); foo==3 && bar==4 => 1
|
|
l(foo, bar, baz) = l(2, 4, 6); l(min(foo, bar), baz) = l(3, 5); l(foo, bar, baz) => [3, 4, 5]
|
|
</pre>
|
|
|
|
In the last example `l(min(foo, bar), baz)` creates a valid L-value, as min(foo, bar) finds the lower of the
|
|
variables (in this case `foo`) creating a valid assignable L-list of [foo, baz], and these values
|
|
will be assigned new values
|
|
|
|
### `join(delim, list), join(delim, values ...)`
|
|
|
|
Returns a string that contains joined elements of the list, iterator, or all values,
|
|
concatenated with `delim` delimiter
|
|
|
|
<pre>
|
|
join('-',range(10)) => 0-1-2-3-4-5-6-7-8-9
|
|
join('-','foo') => foo
|
|
join('-', 'foo', 'bar') => foo-bar
|
|
</pre>
|
|
|
|
### `split(delim, expr)`
|
|
|
|
Splits a string undr `expr` by `delim` which can be a regular expression
|
|
|
|
<pre>
|
|
split('',foo) => [f, o, o]
|
|
split('.','foo.bar') => []
|
|
split('\\.','foo.bar') => [foo, bar]
|
|
</pre>
|
|
|
|
### `slice(expr, from, to?)`
|
|
|
|
extracts a substring, or sublist (based on the type of the result of the expression under expr with
|
|
starting index of `from`, and ending at `to` if provided, or the end, if omitted
|
|
|
|
<pre>
|
|
slice(l(0,1,2,3,4,5), 1, 3) => [1, 2, 3]
|
|
slice('foobar', 0, 1) => 'f'
|
|
slice('foobar', 3) => 'bar'
|
|
slice(range(10), 3, 5) => [3, 4, 5]
|
|
slice(range(10), 5) => [5, 6, 7, 8, 9]
|
|
</pre>
|
|
|
|
### `sort(list), sort(values ...)`
|
|
|
|
Sorts in the default sortographical order either all arguments, or a list if its the only argument.
|
|
It returns a new sorted list, not affecting the list passed to the argument
|
|
|
|
<pre>sort(3,2,1) => [1, 2, 3]
|
|
sort('a',3,11,1) => [1, 3, 11, 'a']
|
|
list = l(4,3,2,1); sort(list) => [1, 2, 3, 4]
|
|
</pre>
|
|
|
|
### `sort_key(list, key_expr)`
|
|
|
|
Sorts a copy of the list in the order or keys as defined by the `key_expr` for each element
|
|
|
|
<pre>
|
|
sort_key([1,3,2],_) => [1, 2, 3]
|
|
sort_key([1,3,2],-_) => [3, 2, 1]
|
|
sort_key(l(range(10)),rand(1)) => [1, 0, 9, 6, 8, 2, 4, 5, 7, 3]
|
|
sort_key(l(range(20)),str(_)) => [0, 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
</pre>
|
|
|
|
### `range(to), range(from, to), range(from, to, step)`
|
|
|
|
Creates a range of numbers from `from`, no greater/larger than `to`. The `step` parameter dictates not only the
|
|
increment size, but also direction (can be negative). The returned value is not a proper list, just the iterator
|
|
but if for whatever reason you need a proper list with all items evaluated, use `l(range(to))`.
|
|
Primarily to be used in higher order functions
|
|
|
|
<pre>
|
|
range(10) => [...]
|
|
l(range(10)) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
map(range(10),_*_) => [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
|
|
reduce(range(10),_a+_, 0) => 45
|
|
range(5,10) => [5, 6, 7, 8, 9]
|
|
range(20, 10, -2) => [20, 18, 16, 14, 12]
|
|
</pre>
|
|
|
|
### `element(list, index)(deprecated)`
|
|
|
|
Legacy support for older method that worked only on lists. Please use `get(...)` for equivalent support, or `.`
|
|
operator. Also previous unique behaviours with `put` on lists has been removed to support all type of
|
|
container types.
|
|
|
|
## Map operations
|
|
|
|
Scarpet supports map structures, aka hashmaps, dicts etc. Map structure can also be used, with `null` values as sets.
|
|
Apart from container access functions, (`. , get, put, has, delete`), the following functions:
|
|
|
|
### `m(values ...), m(iterator), m(key_value_pairs)`
|
|
|
|
creates and initializes a map with supplied keys, and values. If the arguments contains a flat list, these are all
|
|
treated as keys with no value, same goes with the iterator - creates a map that behaves like a set. If the
|
|
arguments is a list of lists, they have to have two elements each, and then first is a key, and second, a value
|
|
|
|
<pre>
|
|
m(1,2,'foo') => {1: null, 2: null, foo: null}
|
|
m() => {} (empty map)
|
|
m(range(10)) => {0: null, 1: null, 2: null, 3: null, 4: null, 5: null, 6: null, 7: null, 8: null, 9: null}
|
|
m(l(1, 2), l(3, 4)) => {1: 2, 3: 4}
|
|
reduce(range(10), put(_a, _, _*_); _a, m())
|
|
=> {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
|
|
</pre>
|
|
|
|
### `keys(map), values(map), pairs(map)`
|
|
|
|
Returns full lists of keys, values and key-value pairs (2-element lists) for all the entries in the map
|