Home » , » TCL - More Array Commands - Iterating and use in procedures

TCL - More Array Commands - Iterating and use in procedures

Written By 1 on Monday, June 11, 2012 | 11:40 PM


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 $array

set array(2) "B"

p

r

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

# Cr

proc 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 w

set name($id,first) $first ;# The
ie can use both fixed and
;# varying parts
}

proc report {db} {

[array names name

upvar $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) 0


addname historical_name

set historical_name(ID) 0

addname fictional_name Mary Poppins
addname fictional_name Uriah Heep
addname fictional_name Frodo Baggins
Rene Descartes

ame Julius Caesar

#
# Some simple report

addname 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

0 Comment:

Post a Comment