Often you will want to loop through the contents of an associative array - without having to specify the elements explicitly. For this the
array names
and array get
commands are very useful. With both you can give a (glob-style) pattern to select what elements you need:foreach name [array names mydata] {puts "Data on \"$name\": $mydata($name)"} # # Get names and values directly #{ puts "Data on \"$name\": $value" }foreach {name value} [array get mydata]
Note, however, that the elements will not be returned in any predictable order: this has to do with the underlying "hash table". If you want a particular ordering (alphabetical for instance), use code like:
foreach name [lsort [array names mydata]] {puts "Data on \"$name\": $mydata($name)"}
While arrays are great as a storage facility for some purposes, they are a bit tricky when you pass them to a procedure: they are actually collections of variables. This will not work:
proc print12 {a} {puts "$a(1), $a(2)"} set array(1) "A"int12 $arrayset array(2) "B" pr
The reason is very simple: an array does not have a value. Instead the above code should be:
proc print12 {array} {upvar $array a(2)" } set array(1) "puts "$a(1), $ aA" set array(2) "B"print12 array
So, instead of passing a "value" for the array, you pass the name. This gets aliased (via the upvar command) to a local variable (that behaves the as original array). You can make changes to the original array in this way too.
Example
## The example of the previous lesson revisited - to get a# more general "database" #{ upvar $db name # Crproc addname {db first last}eate a new ID (stored in the name array too for easy access)incr name(ID) set id $name(ID)ndex is simply a string! set name($id,last) $last ;# So wset name($id,first) $first ;# The ie can use both fixed and ;# varying parts } proc report {db} {[array names nameupvar $db name # Loop over the last names: make a map from last name to ID foreach n "*,last"] { # # Split the name to get the ID - the first part of the name! #ap of last name to ID)regexp {^[^,]+} $n id # # Store in a temporary array: # an "inverse" m # set last $name($n) set tmp($last) $id } #h last [lsort [array names tmp]] { set id $tmp($last)# Now we can easily print the names in the order we want! # forea c puts " $name($id,first) $name($id,last)" } } # # Initialise the array and add a few names # set fictional_name(ID) 0addname historical_nameset historical_name(ID) 0 addname fictional_name Mary Poppins addname fictional_name Uriah Heep addname fictional_name Frodo Baggins Rene Descartesame Julius Caesar # # Some simple reportaddname historical_name Richard Lionheart addname historical_name Leonardo "da Vinci" addname historical_name Charles Baudelaire addname historical_ ning # puts "Fictional characters:" report fictional_name puts "Historical characters:"report historical_name
No comments:
Post a Comment