Part III Tcl Data Structures
1 More about Variables
- The set command
In the last command,
$name gets substituted with
var. Then the
set command returns the value of
var, which is
the value of var. Another way to achieve a level of indirection like this is with nested
set commands. The last
set command above can be written as follows:
set [set name]
=> the value of var
unset varName varName2 ...
e.g.
if ![info exists foobar]{
set foobar 0
} else {
incr foobar }
e.g. Constructing a list with the list command
set x {1 2}
=> 1 2
set x
=> 1 2
list $x /$ foo
=> {1 2} {$} foo
[Note]: The braces used to group the list value into one argument to the set command are not part of the list value.
The lappend command is used to append elements to the end of a list. You can call lappend with the name of an undefined variable and the variable will be created.
e.g.
lappend new 1 2
=> 1 2
lappend new 3 "4 5"
=> 1 2 3 {4 5}
set new
=> 1 2 3 {4 5}
The concat command is useful for splicing together lists. It works by concatenating its arguments together, separating them with spaces. This multiple lists into one where the top-level list elements in each input list are also top-level list elements in the resulting list.
e.g. Using concat to splice together lists.
concat 1 {2 3} {4 5 6}
=> 1 2 3 4 5 6
It turns out that double quotes behave much like the concat command.
e.g. Double quotes compared to the list command.
set x {1 2}
=> 1 2
set y "$x 3"
=> 1 2 3
set y [concat $x 3]
=> 1 2 3
set z [list $x 3]
=>{1 2} 3
The basic rule is that list and lappend preserve preserve list structure, while concat(or double-quotes)eliminate one level of list structure.
The lindex command returns a particular element of a list. It takes an index. List indices count from zero. The keyword end means the last element, and it can be used with lindex, linsert, lrange and lreplace.
e.g.
lindex {1 2 3} 0
=> 1
lindex {1 2 3} 2
=> 3
The lrange command returns a range of list elements. It takes a list and two indices as arguments.
e.g.
lrange {1 2 3 {4 5}} 2 end
=> 3 {4 5}
lreplace is used to replace a range of list elements with new elements. If you don't specify any new elements, you effectively delete elements from a list.
e.g.
linsert {1 2} 0 new stuff
=> new stuff 1 2
set x [list a {b c} e d]
=> a {b c} e d
lreplace $x 1 2 B C
=> a B C d
lreplace $x 0 0
=> {b c} e d
The example below uses lreplace to delete elements by not specifying any replacement list elements.
e.g.
proc delete {list value} {
set ix [lsearch -exact $list $value]
if {$ix>=0} {
return [lreplace $list $ix $ix]
} else {
return $list
}
}
The default split character is white space. If there are multiple separator characters in a row, these result in empty list elements- the separators are not collapsed. The following command splits on commas, periods, spaces and tabs:
The
join command is the inverse of split. It takes a list value and reformats it with specified characters separating the list elements. In doing so, it will remove any curly braces from the string representation of the list that are used to group the top-level elements.
e.g. set arra(index) value
The value of an array element is obtained with $ substitution:
e.g. set foo $arr(index)
If you have complex indices, use a comma to separate different parts of the index. Avoid putting a pace after the comma. It is legal, but a space in an index value will cause problems because parenthesis are not used as a grouping mechanism. The space in the index needs to be quoted with a backslash, or hte whole variable reference needs to be grouped:
e.g. set {arr(I'm asking for trouble)} {I told you so.}
If the array index is stored in a variable, then there is no problem with spaces in the variable's value. The following works fine:
e.g.
set index { I'm asking for trouble }
set arr($index) { I told you so. }
The name of the array can be the result of a substitution. If the name of the array is stored in another variable, then you must use set as shown in the last command below to reference the array elements.
The array names command is perhaps the most useful because it allows easy iteration through an array with a foreach loop:
foreach index [array names arr] {command body}
The order of the names returned by array names is arbitrary. It is essentially determined by the hash table implementation of the array.
The array get and array set operations are used to convert between an array and a list. The list returned by array get has an even number of elements.The first element is an index, and the next is the corresponding array value. The ordering of the indexes is arbitrary. The list argument to array set must have the same structure.
trace variable name ops command
The name is a Tcl variable name, which can be a simple variable, an array or a element.If a whole array is traced, then the trace is invoked when any element is used according to ops. The ops argument is one or more of the letters: r for read traces, w for write traces, and u for unset traces. The command is executed when one of these events occurs. It is invoked as:
command name1 name2 op
Information about traces on a varible is returned with the vinfo option.
trace vinfo dynamic
=> {r FixDynamic}
A trace is deleted with the vdelete trace option, which has the same form as the varible option.
set [set name]
=> the value of var
- The unset command
unset varName varName2 ...
- Using info to find out about variables
e.g.
if ![info exists foobar]{
set foobar 0
} else {
incr foobar }
2 Tcl Lists
The Tcl list has the same structure as a Tcl command. That is, a list is simply a string with list elements separated by white space.Braces or quotes can be used to group words with whitespace into a single list element.3 Constructing Lists: list, lappend and concat
The list command constructs a list out of its arguments such that there is one list element for each argument. if any of the arguments contain special characters, the list command adds some quoting to ensure they are parsed as a single element of the resulting list.set x {1 2}
=> 1 2
set x
=> 1 2
list $x /$ foo
=> {1 2} {$} foo
[Note]: The braces used to group the list value into one argument to the set command are not part of the list value.
The lappend command is used to append elements to the end of a list. You can call lappend with the name of an undefined variable and the variable will be created.
e.g.
lappend new 1 2
=> 1 2
lappend new 3 "4 5"
=> 1 2 3 {4 5}
set new
=> 1 2 3 {4 5}
The concat command is useful for splicing together lists. It works by concatenating its arguments together, separating them with spaces. This multiple lists into one where the top-level list elements in each input list are also top-level list elements in the resulting list.
e.g. Using concat to splice together lists.
concat 1 {2 3} {4 5 6}
=> 1 2 3 4 5 6
It turns out that double quotes behave much like the concat command.
e.g. Double quotes compared to the list command.
set x {1 2}
=> 1 2
set y "$x 3"
=> 1 2 3
set y [concat $x 3]
=> 1 2 3
set z [list $x 3]
=>{1 2} 3
The basic rule is that list and lappend preserve preserve list structure, while concat(or double-quotes)eliminate one level of list structure.
4 Getting List Elements: llength, lindex, and lrange
The llength command returns the number of elements in a list.The lindex command returns a particular element of a list. It takes an index. List indices count from zero. The keyword end means the last element, and it can be used with lindex, linsert, lrange and lreplace.
e.g.
lindex {1 2 3} 0
=> 1
lindex {1 2 3} 2
=> 3
The lrange command returns a range of list elements. It takes a list and two indices as arguments.
e.g.
lrange {1 2 3 {4 5}} 2 end
=> 3 {4 5}
5 Modifying Lists: linsert and lreplace
The linsert command inserts elements into a list value at a specified index. If the index is 0 or less, then elements are added to the front. If the index is equal to or greater than the length of the list, then the elements are appended to the end. Otherwise, the elements are inserted before the element that is currentl as position index.lreplace is used to replace a range of list elements with new elements. If you don't specify any new elements, you effectively delete elements from a list.
e.g.
linsert {1 2} 0 new stuff
=> new stuff 1 2
set x [list a {b c} e d]
=> a {b c} e d
lreplace $x 1 2 B C
=> a B C d
lreplace $x 0 0
=> {b c} e d
6 Searching Lists: lsearch
lsearch returns the index of a value in the list, or -1 if it is not present. lsearch supports pattern matching in its search. Glob-style pattern matching is default, and this canbe disabled with the -exact flag.The example below uses lreplace to delete elements by not specifying any replacement list elements.
e.g.
proc delete {list value} {
set ix [lsearch -exact $list $value]
if {$ix>=0} {
return [lreplace $list $ix $ix]
} else {
return $list
}
}
7 Sorting List: lsort
The three basic types of sorts are specified with the -ascii, -integer, or -real options. The -increasing or -decreasing option indicate the sirting order. The default option set is -ascii -increasing.8 The split And join Commands
The split command takes a string and turns it into a list by breaking it at specified characters. Stray double-quotes or curly braces in the input can result in invalid list structures and errors in your script. However, the split command provides a robust way to turn input lines into proper Tcl lists.9 Arrays
The index of an array is delimited by parentheses. The index can have any string value, and it canbe the result of variable or command substitution.e.g. set arra(index) value
The value of an array element is obtained with $ substitution:
e.g. set foo $arr(index)
e.g. set {arr(I'm asking for trouble)} {I told you so.}
If the array index is stored in a variable, then there is no problem with spaces in the variable's value. The following works fine:
e.g.
set index { I'm asking for trouble }
set arr($index) { I told you so. }
The name of the array can be the result of a substitution. If the name of the array is stored in another variable, then you must use set as shown in the last command below to reference the array elements.
10 The Array Command
foreach index [array names arr] {command body}
The order of the names returned by array names is arbitrary. It is essentially determined by the hash table implementation of the array.
The array get and array set operations are used to convert between an array and a list. The list returned by array get has an even number of elements.The first element is an index, and the next is the corresponding array value. The ordering of the indexes is arbitrary. The list argument to array set must have the same structure.
11 Environment Variables
In UNIX, the process environment variables are available through the global array env. The name of the environment variable is the index,e.g. env(PATH), and the array element contains the current value of the environment variable.12 Tracing Variable Values
The trace command lets you register a command to be called whenever a variable is accessed, modified or unset. The form is:trace variable name ops command
The name is a Tcl variable name, which can be a simple variable, an array or a element.If a whole array is traced, then the trace is invoked when any element is used according to ops. The ops argument is one or more of the letters: r for read traces, w for write traces, and u for unset traces. The command is executed when one of these events occurs. It is invoked as:
command name1 name2 op
trace vinfo dynamic
=> {r FixDynamic}
A trace is deleted with the vdelete trace option, which has the same form as the varible option.