# List and Set Operators

A list is a list of strings or tags separated by semicolons.

`Arwen; Eowyn; Galadriel`

A set is a list where duplicate values are not allowed. A given element can appear in a set at most once; duplicates are automatically removed.

The order of elements in a set is not significant, and Tinderbox controls the order of elements in a set. You determine the order of elements in a list.

Two lists or sets are equal if they contain the same elements.

Adding and Removing Items

The operators + and - add and remove items from lists and sets.

> `$MySet = $MySet + "important"`

adds the value “important” to $MySet. Since sets cannot contain duplicates, this will have no effect if $MySet already contains "important".

> `$MyList = $MyList + "important"`

adds "important" to the end of $MyList. Since lists can contain duplicate entries, this always changes $MyList.

You can add more than one tag at a time:

> `$MySet = $MySet+"important;overdue"`

You can also add a list or set to another list or set:

> `$MySet = $MySet + $UrgentTags`

Similarly, subtraction removes tags from a set or list:

> `$MySet = $MySet - "important"`

removes "important" from $MySet. If $MySet does not contain "important", this action will have no effect.

List/Set.contains("item") - true if any element of the List or Set matches the quoted string "item" exactly. Matches are case-sensitive. Match values must be enclosed in quotes. The returned value is the zero-based offset of the match +1.

"Arwen;Eowyn;Galadriel".contains("Eowyn") | 2
"Arwen;Eowyn;Galadriel".contains("Frodo") | 0

list.at(n) – returns the nth item in the list. If n is zero, returns the first item. If n is negative, returns the nth item from the end of the list. If the list does not contain n items, returns the empty string.

list.at("keyword") – extracts a value from a list, string, or set of keyword-value pairs in which the keyword and value are separated by colons. For example, suppose

`$MyString = "USA: North America; Canada: North America; France: Europe; Japan: Asia; default: unknown"`

Then

`$MyString.at("France") ==> "Europe"` `$MyString.at("Canada" => "North America"`

The special keyword "default" applies to any keyword not contained in the list. For convenience, when several keywords have the same value they may be separated by pipe characters “|”:

`"USA | Canada: North America; …"`

List/Set.each(n){...actions... } – performs an action for each element of the list or set. The local variable "n" is bound to each element in turn. For example:

> `$Result=0; $MyList.each(x){ $Result=$Result+x;}`

adds each element to $Result

List/Set.empty - true if the List or Set has no elements.

List/Set.format("delimiter") - converts a List or Set to String-type data, concatenating each value with the specified "delimiter" characters. thus if "delimiter" is ", " the source data becomes as comma+space delimited list as a single String.

List/Set.format("list-prefix", "item-prefix", "item-suffix", "list-suffix") - converts a List or Set to a String. The list begins with the "list-prefix" and ends with "list-suffix"; each item is preceded by "item-prefix" and followed by"item-suffix".

List/Set.icontains("item") - true if any element of the List or Set matches the quoted string "item" exactly; differences between upper and lower-case letters are ignored. Regular expressions are not supported (unlike with pure string operations). Matches are case-insensitive. Match values must be enclosed in quotes. The returned value is the zero-based offset of the match +1. The latter is to ensure that matches are always 1 or more and thus also coerce to 'true' for the true/false element of testing for match.

List/Set.intersect(list) - returns the intersection of two sets or lists — a set or list of the values shared by each.

List/Set.replace("item","replace") - replaces the designated item with a replacement value. Matches are only the whole list values; partial value matches are not supported. Match values must be enclosed in quotes.

List/Set.size - the number of values in the the list. Read-only property.

#### Sorting

Lists (but not sets) may be sorted. The following sort operations apply only to lists:

List.sort - case-sensitive sort

List.isort - case-insensitive sort().

List.nsort([expression]) - nsort() behaves exactly like sort(), but assumes that the list elements, are numbers.

List.sort([expression]) - if List is a list of note names or $Paths, returns a list sorted by the corresponding expression (or attribute value). If expression is a Number-type, a numeric sort is used; if Date-type, a date sort is used. Otherwise, the list is sorted lexically.

List.isort([expression]) - as above but case-insensitive.

List.nsort([expression]) - numeric sort. An nsort() behaves exactly like sort(), but assumes that the list elements, or the result of the optional expression, are numbers. Thus an nsort() always sorts numerically.

List.reverse - reverses the sequence of items in the list.

For example, suppose $Favorites is a list of favorite notes.

> `$Favorites.sort($Price)`

returns a list of notes sorted by price with the lowest price first, and

> `$Favorites.sort($Price).reverse`

is sorted by price with the highest price first.

List.unique() - returns a new list that contains each unique item found in the source list. Duplicate entries are not copied. Note that all items in a Set are, by definition, unique.

#### List Operations

Several functions are useful for extracting notable elements from sets and lists. In the following, the list argument implies set or list data.

count(list) returns the number of tags in list.

max(list) returns the largest tag in list

min(list) returns the smallest tag in list

If max(list) or min(list) is evaluated in a numerical context, numerical comparison is used. Otherwise, Tinderbox uses lexical comparison.

The mathematical functions sum(), sum_if() and avg_if() take a group scope (i.e a list of $Paths) so can be used with lists - see Numeric Functions further above.

#### Building Lists

collect(group,expression) builds a list by visiting each note described by group and adding the value of the designated attribute to the list. For example,

> `collect(children,$Name)`

constructs a list with the name of each child of the note. group may be any group designator: {children,descendants,sibling,ancestor,all}. In addition, group may take a path modifier; for example

> `collect(children(/agents/books),$Name)`

expression can be any expression, but is typically an attribute.For example,

> `collect(children,$Name)`

> `collect(children,$Width*$Height)`

collect_if(group,condition,expression) constructs a list by collecting all the notes corresponding to group, testing each note to see if it meets condition, and adding the expression to the set for each such note. For example

> `collect_if(children,$Status="Important",$Name)`

will construct a set of the names of all of this note's important children.

Should a unique list of values be required, pass the output to a Set to remove duplicate values.

find(query) is equivalent to

> `collect_if( all, query, $Path)`

Note that `collect_if` is related to agents; many tasks you might perform with collect_if can be done as well, or better, with an agent. The results of an agent can be reused by other agents, while find() and collect_if() need to start from scratch each time they are run.

values("attribute_name") returns a set of unique values stored in that attribute throughout the document. If the attribute is a set or a list, values() returns a set of unique elements used throughout the document; if the attribute is a any other type, values() returns each of the distinct values in use.