Reputation: 111
I want to use name of name in array. I searched about dictionary but my tcl version is old so I couldn't use dictionary. also I couldn't upgrade tcl version. So Could you tell me how to use name of name like below script..?
set country korea
set food kimchi
set find($country)($food) spicy
set country japan
set food susi
set find($country)($food) fresh
set country international
set food hamburger
set find($country)($food) standard
set country international
set food chicken
set find($country)($food) standard
foreach country [array names find] {
puts $index
}
# I expect 'korea japan international'.. but It wasn't working
foreach country [array names find] {
foreach food [array names find($country)] {
puts $country,$food,$food($country)($food)
}
}
# I expect
# korea,kimch,spicy
# japan,susi,fresh
# international,hamburger,standard
# international,chicken,standard
# but It was not working..
Upvotes: 0
Views: 55
Reputation: 137627
If you can't use dictionaries, this means you're on Tcl 8.4 or before. These are not supported; the minimum supported version of Tcl is 8.5 which is currently on long-term critical-bug-fix only grade support, and 8.6 is the recommended minimum for new work. The formal advice is upgrade, even if this is impossible for you.
So, you're stuck with dictionaries? You cannot nest those (except in a few ancient versions where it was possible via a bug) so you need to find a different approach. The simplest method might be to use one array that holds the name of another array. This is probably easiest if we use a few helper procedures:
# Initialise the array ahead of time
array set find {}
proc setFoodInfo {country food info} {
upvar 1 find find
if {![info exists find($country)]} {
# Generate a unique array name
set find($country) find_[array size find]
}
upvar 1 $find($country) ary
set ary($food) $info
return
}
proc listFoods {country} {
upvar 1 find find
upvar 1 $find($country) ary
return [array names ary]
}
proc getFoodInfo {country food} {
upvar 1 find find
upvar 1 $find($country) ary
return $ary($food)
}
setFoodInfo korea kimchi spicy
setFoodInfo japan sushi fresh
setFoodInfo international hamburger standard
setFoodInfo international chicken standard
foreach country [array names find] {
foreach food [listFoods $country] {
puts $country,$food,[getFoodInfo $country $food]
}
}
When I test it in Tcl 8.4 — I fortunately still have a copy — I get this output:
international,chicken,standard international,hamburger,standard japan,sushi,fresh korea,kimchi,spicy
Tcl doesn't preserve the order of arrays, so I consider this to be acceptably similar to what you are looking for.
The actual most common technique back in old Tcl versions was to use compound keys, often with ,
as the compounding character:
set find(korea,kimchi) spicy
...
foreach name [array names find] {
puts $name,$find($name)
}
but this gets quite confusing when you want to ask questions like “what countries do I have information about foods for?”. It's not insurmountable for reasonable keys, as you can use a glob pattern with array names
and parse the result (e.g., with split
or regexp
), but it's quite messy. (For this particular example, the best answer is to use an SQL database, but that involves an extra package and possibly more external setup.)
Upvotes: 1