简体   繁体   中英

How to print multiple arrays in TCL?

#!/usr/bin/expect -f

set myarr1(chicken) animal
set myarr1(cows) animal
set myarr1(tiger) animal
set myarr1(horse) animal

set myarr2(carrot) vegetable
set myarr2(tomato) vegetable
set myarr2(potato) vegetable
set myarr2(pea) vegetable

set arr_list { myarr1 myarr2 }

foreach key [array names [lindex $arr_list 0]] {
    puts "${key}=$[lindex $arr_list 0]($key)"
}

foreach key [array names [lindex $arr_list 1]] {
    puts "${key}=$[lindex $arr_list 1]($key)"
}

Output obtained:

cows=$myarr1(cows)
horse=$myarr1(horse)
chicken=$myarr1(chicken)
tiger=$myarr1(tiger)
tomato=$myarr2(tomato)
pea=$myarr2(pea)
potato=$myarr2(potato)
carrot=$myarr2(carrot)

Required output:

cows=animal
horse=animal
chicken=animal
tiger=animal
tomato=vegetable
pea=vegetable
potato=vegetable
carrot=vegetable

I am able to get the required output if I use the following in foreach loop:

foreach key [array names myarr1] {
    puts "${key}=$myarr1($key)"
}

foreach key [array names myarr2] {
    puts "${key}=$myarr2($key)"
}

I am trying to create a list of array names and then loop through that list of array names and print it. If there is a better way to approach this problem, I am all ears. Thanks for the assist !

You really ought to use nested foreach s for that.

foreach arr $arr_list {
    foreach key [array names $arr] {
        puts "${key}=$$arr($key)"
    }
}

Except that doesn't work! Why? It's easy on one level: the syntax for $ doesn't support such complexity; it really only supports a (very useful) subset of legal variable names and can't do complicated substitutions (array element names support more diverse options). We need to rewrite to use the single-argument set form as a first step:

foreach arr $arr_list {
    foreach key [array names $arr] {
        puts "${key}=[set [set arr]($key)]"
    }
}

That works, but isn't very elegant (or fast, for that matter). It's actually better to use upvar 0 to make a local alias to the array that you're processing; variable alias from a to whatever was talked about with $arr will let us shorten things elsewhere, and it's pretty elegant in practice:

foreach arr $arr_list {
    upvar 0 $arr a
    foreach key [array names a] {
        puts "$key=$a($key)"
    }
}

You can also do things like sorting the list of element names ( array names does not guarantee to return things in any particular order), putting spacing in between each of the arrays that you print out, etc. But that's the core of how to improve things. You can also use array get instead of array names and a multi-variable foreach , but then sorting the keys is more awkward (well, before Tcl 8.6's lsort gained the -stride option).

If you just want to print them, use the bundled parray proc :

foreach arr $arr_list {
    parray $arr
}

which outputs

myarr1(chicken) = animal
myarr1(cows)    = animal
myarr1(horse)   = animal
myarr1(tiger)   = animal
myarr2(carrot) = vegetable
myarr2(pea)    = vegetable
myarr2(potato) = vegetable
myarr2(tomato) = vegetable

You can use the foreach command to traverse both the keys and the values in the array.

array set arr {a 1 b 2 c 3}
foreach {k v} [array get arr] {
  puts $k=$v
}

References: foreach

You're on the right track with the foreach command, but to loop over the list of arrays you need to nest it:

foreach arr $arr_list {
    foreach {key val} [array get arr] {
        puts "$key = $val"
    }
}

Also, look into the parray command, and see if that style of printing works for what you need. (I'd link it, but the site appears to be down at the moment. I'll try to remember to edit this later. Check out the command details at http://www.tcl.tk/man/tcl8.6/ )

What you probably want is:

foreach arr $arr_list {
    foreach key [array names $arr] {
        puts "$key=[set ${arr}($key)]"
    }
}

That said, you're using arrays in a non-standard way that possibly is suboptimal. Have you looked into dictionaries? (Unfortunately, discussing how your data should be structured isn't a Stackoverflow topic.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM