Lists
A second fundamental data structures in Frag, besides objects and strings, are lists.
A list contains a number of elements separated by whitespaces. For instance a method definition:
A method myMethod {a b c} {
puts "$a $b $c"
}
is a list of 5 elements: object name, the method operation name, method name, argument list, and body.
Actually, each invocation in Frag is a list.
The elements of a list can either be strings (or what they are converted to internally,
like object names or integers), or other lists. For instance, the argument list a b c
in the method definition above is an
embedded list. Lists can be delimited using curly braces {...}.
Sometimes lists that are stored in variables or returned by commands are in
an unhandy format, because they are not expanded, but an expanded list is needed.
Consider the following example:
Command create sum -cmd {args} {
set result 0
foreach n $args {
set result ($result + $n)
}
return $result
}
This method calculates the sum of an arbitrary number of arguments in a list.
But this only works with an expanded list, such as the following:
sum 1 2 3
The following would not work:
set a {1 2 3}
sum $a
This would yield the error "value '1 2 3' is not a number" because
a list with only one element {1 2 3} is given as a argument and Frag does not
know how to convert {1 2 3} into a number that can be used in the addition.
We can avoid this
by using the expand syntax, which uses * after $ or opening square brackets:
$* or [* ...] to expand the list.
Hence the following variable expansion works:
set a {1 2 3}
sum $*a
Similarly, invocation expansion works as well:
set a {1 2 3}
sum [* get a]
The expand syntax can be used on any variable read using $ or any invocation in
square brackets.
The command list offers a number of methods for manipulating lists. All
list methods have no side effect on the lists used as input - they only manipulate
the result list. In addition, there is the command append (explained first)
which modifies a list in a variable. This command is more efficient than copying lists
to and from variables; hence, it should be used for the common use case of incrementally
building up a list variable (e.g., using a for or foreach loop).
append <variableName> ?new elements ...?
append appends an arbitrary number of new elements to a given list stored in
variableName.
The following code returns the list a b c 0 2:
set a {a b c}
append a 0 2
get a
list build ? list elements ...?
list build explicitly tells the interpreter to build a list from an arbitrary
number of arguments. Without argument, list build returns an empty list.
The following simple example builds a list of two elements: {a b} and c,
the first being itself a list of two elements (a and b).
list build {a b} c
list delete <list> <element>
Options: -first, -all
list delete deletes the list element element from list. Per default
only the first element is deleted (this can also be specified using -first).
Optionally, -all specifies that all occurrences of element are deleted from list.
The following code deletes the first element e from the list.
The result is the list a b cd e.
list delete {a b cd e e} e
The following code deletes all elements e from the list.
The result is the list a b cd.
list delete -all {a b cd e e} e
list index <list> <index>
list index returns the index-th element in the list. Counting starts with 0.
The following code returns a b because this is the element of the list at index 0.
list index {{a b} c d e} 0
The following code returns d because this is the element of the list at index 2.
list index {{a b} c d e} 2
list insert <list> <index> <insert list>
list insert inserts the elements of the list insert list
at index into the list
and returns the modified list.
The following code returns a b b2 b3 c:
list insert {a b c} 2 {b2 b3}
list join <list> ?join string?
list join returns a string formed by joining all of the
elements of list together using join string for
separating each adjacent pair of elements.
The join string argument defaults to a space character.
The following code returns the string: a, b, clist join {a b c} ", "
list length <list>
list length returns the number of list elements in list.
The following code returns 2, because the list built by list build has two elements: {a b} and c.
list length [list build {a b} c]
list replace <list> <index1> <index2> <new list>
list replace replaces the content of list from index1 to index2
with the content of the new list argument. If the new list is empty the
elements in the lists get deleted.
The following code replaces the elements from index 2 to 4 of the given
list with the list 5 6 7. The result is: a b 5 6 7 f.
list replace {a b c d e f} 2 4 {5 6 7}
The following code deletes the elements from index 1 to 3 of the given
list (i.e., replaces them with an empty list). The result is the list a e.
list replace {a b cd e e} 1 3 {}
list search ?-options ...? <list> <match string>
Options: -exact, -pattern, -first, -all, -indices, or -elements
list search searches through a list for a given match string. There
are a number of options for a search which can be combined. A search can either
be an exact search (specified by -exact) or a search using pattern matching
(specified by -pattern). For details on pattern matching see Section
Pattern Matching. -pattern is the default.
The search can either return only the first match (specified by -first) or
all matching results (specified by -all). -first is the default. Finally,
a search can return the indices that match (specified by -indices) or the list of elements that
match (specified by -elements). -indices is the default.
Without options, the default options are assumed. Hence the following search
returns the index of the first exact match: 1.
list search {1 2 3 4 12 22 23} 2
We can use the -all option to find all indices of all matches:
list search -all {1 2 3 4 12 22 23} 2
The above example still returns only 1 because that's the only exact match,
but if we additionally activate pattern matching, 1 5 6 is found:
list search -all -pattern {1 2 3 4 12 22 23} 2*
If we want the elements that match rather than the indices, we need to use
the elements option, and get the result 2 22 23:
list search -all -pattern -elements {1 2 3 4 12 22 23} 2*
list sort ?-options ...? <list>
Options: -ascii, -object, -decreasing, -dictionary, -increasing, -integer, or -double
list sort
sorts the list following the sort criteria given as (optional) options
and returns the sorted list.
The sort mode defines how values are compared. The default is -ascii,
which performs a lexical comparison of the ascii values of each letter
of the list elements (i.e., they are treated as strings).
The -dictionary option also performs a lexical comparison, but following
dictionary rules instead of a lexical comparison character by character. For instance,
in -ascii mode Item 11 comes after Item 100, because the character 0 has a lower
ascii value than 1, but in -dictionary mode, Item 11 comes before Item 100.
The -integer option tries to convert all list elements
to integers and sorts the list using an integer value comparison. The -double option
tries to convert all list elements
to doubles and sorts the list using double value comparison.
In both cases, if a list element cannot be
converted, an error is thrown.
The -object option takes an object ID as argument. This object is used
for comparison. The object must be a Command (see User-defined Commands), which takes two values to compare
as arguments, such as:
Command create compareCmd -cmd {a b} {...}
The Command works
equally to the string compare (see string compare) method. That is,
the result is "-1" if argument a precedes argument b.
The result is a "1" if argument a follows argument b.
The result is zero if a and b are equal.
The option -decreasing sorts the list in decreasing fashion
(according to the other search criteria), and -increasing returns the increasingly sorted
list. -increasing is the default.
The following simple example returns the list 1 a ab abdeq ac, which is the
list sorted by a standard increasing lexical comparison.
list sort {abdeq ab 1 ac a}
Here the default -increasing is chosen. The same search with
-decreasing returns
the list ac abdeq ab a 1:
list sort -decreasing {abdeq ab 1 ac a}
To sort an integer list, we can issue the following invocation. It returns:
-42 1 33 40 62 180 180:
list sort -integer {1 180 62 040 180 -42 33}
This can also be combined with -decreasing, which then returns: 180 180 62 40 33 1 -42.
list sort -int -decreasing {1 180 62 040 180 -42 33}
The following code demonstrates the -dictionary option:
set l {a1 a11 a100 a101 a10 a12 a15}
set r1 [list sort $l]
set r2 [list sort -ascii $l]
set r3 [list sort -dictionary $l]
puts "list build $r1 $r2 $r3"
This code prints:
{a1 a10 a100 a101 a11 a12 a15} {a1 a10 a100 a101 a11 a12 a15} {a1 a10 a11 a12 a15 a100 a101}
The first two lists are sorted in -ascii mode. Hence, a100 a101 precede a11 a12 a15. This is not the case in
-dictionary mode: Here the standard dictionary sorting rules are applied.
The following creates a sorter command and uses this custom sorter to
sort a list by the first list elements of its sub-lists.
Command create sorter -cmd {a b} {
string compare [list index $a 0] [list index $b 0]
}
list sort -object sorter -dec {{1 a b c} {2 b c} {5 d e} 4}
Of course, Command objects can also be inlined as unnamed objects. The example
above could hence be modified to the following shorter form:
list sort -object [Command create -cmd {a b} {
string compare [list index $a 0] [list index $b 0]
}] -dec {{1 a b c} {2 b c} {5 d e} 4}
list split <string> ?split string?
list split returns a list that is formed by splitting the given string
at each position where split string occurs in the string.
The split string argument defaults to a space character.
The following code returns the list: {a b c}
list split {a, b, c} ", "
list subList <list> <index1> <index2>
list subList returns a list which is the sub-list (i.e. a specific subList)
from index1 to index2 of a given list.
The following code returns the list b cd e:
list subList {a b cd e e} 1 3
The list subList command in the following code returns the sub-list
of l ranging from the second element to the last element:
set l {a b c}
list subList $l 1 ([list length $l] - 1)