2
votes

Is it possible to do nested associative arrays in Tcl? I know I can use 'dict' in tcl8.5 or higher, but my code needs to run on tcl8.4.

I'm looking to do this:

array set A {}
array set tmp {...}
array set tmp1 {...}
array set A($foo) tmp
array set A($foo1) tmp1

So foo/foo1 are keys and their values are associative arrays. In python, this would be like a dict of dicts.

I am trying the above but tcl is complaining A($foo)/A($foo1) is not an array.

1
No, tcl arrays are strictly one-dimensional. You can construct complicated strings for the keys to fake multi-dimensionality: set A(foo,bar,baz) quxglenn jackman
Or, array values can be lists, so set A($foo) [array get tmp]glenn jackman
My best attempt was upvar 0 arrayvar(key) refvar ; array set refvar {key value}. It does not work: refvar does not exist yet, but is already blocked to not become an array.MKaama

1 Answers

3
votes

Tcl's arrays cannot be nested (except in very old versions of Tcl, where there were bugs which let you do it). You can often use a composite key such as a,b,c (or $a,$b,$c) to achieve a similar effect, but that's really just leveraging the fact that keys are general strings and not numbers or simple words.

set A(123,$xyz) "the quick brown $fox"
set B($pqr,456) "the lazy dogs"

In addition to this, you can't really put references to variables in variables. You'd have to do some additional munging:

foreach {key value} [array get tmp1] {
    set A($foo,$key) $value
}

Tcl 8.5's dictionaries (where the mapping is a value, not a variable collection) would indeed be a better solution for the things you're looking to do, particularly since 8.4 is now entirely end-of-lifed (and I know of some really nasty bugs in it that won't be fixed). I think there's a dict package that implements a partial backport of the functionality for 8.4, but I'm not entirely sure about that as I didn't do the packaging and had already moved on to 8.5 at that point; it won't be maintained…