0

In TCL, I have a few arrays whose names have a numeric suffix (i.e., whose names end with a number), like below:

array set ps0 [ list 0 15.885 1 55.43 1 0.254 2 0.227 3 0.177 ]
array set ps1 [ list 0  6.585 1 56.43 1 0.254 2 0.227 3 0.177 ] 
array set ps2 [ list 0 32.485 1 43.13 1 0.254 2 0.227 3 0.177 ] 

I need to iterate over these in TCL and get the values, but, no matter what I do to escape the numeric suffix, I cannot get both the array and the contents.  Everything I've tried, such as:

ps$i($i)
"ps$i($i)"

or even using a set like:

set p ps$i

...does not work to get the array with the number index.  I get the error:

Original error: can't read "ps": no such variable

...for all possible combinations.  How can I do this (in TCL)?

2 Answers 2

2

Any time you're trying to build a variable name at runtime, it's a big sign you're Doing It Wrong and should be using a dict instead (Usually easier to work with all around than arrays). In this case, a multi-dimensional dictionary:

dict set ps 0 [dict create 0 15.885 1 55.43 1 0.254 2 0.227 3 0.177]
dict set ps 1 [dict create 0 6.585 1 56.43 1 0.254 2 0.227 3 0.177]
dict set ps 2 [dict create 0 32.485 1 43.13 1 0.254 2 0.227 3 0.177]

puts [dict get $ps 1 0] ;# 6.585
dict set ps 1 0 3.14159 ;# Change it to pi

# Print out all the key-value pairs in the ps dict associated with 0
dict for {k v} [dict get $ps 0] {
    puts "$k\t$v"
}

The documentation for variable substitution says of $name(index):

Name gives the name of an array variable and index gives the name of an element within that array. Name must contain only letters, digits, underscores, and namespace separators, and may be an empty string. Letters and digits are only the standard ASCII ones (0–9, A–Z and a–z)

so that's part of why things like ps$i($i) aren't working for you - there's no variable substitution done in the name. And in that example it's looking for an array variable named i anyways.

1
  • ok, this makes a LOT more sense like this. I am used to high level compiled languages and this caught me off guard as it seemed so trivial. it seems I have a lot more to learn about the intricacies of TCL and the internal structure of some of these foundational concepts. thank you!
    – poppycock
    Commented Feb 16, 2024 at 7:48
0

dicts are clearly the better choice here.

There is a way to get this work with arrays. Use upvar to link the dynamic name to a "temporary" one

foreach i {0 1 2} {
    puts "ps$i"
    upvar 0 ps$i tmp
    parray tmp
}
ps0
tmp(0) = 15.885
tmp(1) = 0.254
tmp(2) = 0.227
tmp(3) = 0.177
ps1
tmp(0) = 6.585
tmp(1) = 0.254
tmp(2) = 0.227
tmp(3) = 0.177
ps2
tmp(0) = 32.485
tmp(1) = 0.254
tmp(2) = 0.227
tmp(3) = 0.177

Since the array keys are sequential integers, I'm wondering why you're not using plain lists.

2
  • That is actually what I had been doing a bit yesterday and it seemed to work ok, but not perfectly. :) I had something like: proc getArrayValue {arrayName index} { upvar 1 $arrayName array if {[info exists array($index)]} { return $array($index) } else { return "" } }. ...this works ok, but the issue was dereferencing in the arrays. TBH I would like to stay with arrays to speed up the lookup but I also profiled the dictionary perf in TCL and it is ok for a script. I was having index alignment issues with things like: [getArrayValue $ps_item 0]
    – poppycock
    Commented Feb 16, 2024 at 17:45
  • WRT to Lists, it was mostly habit. I will look now, thank you. I am dealing with sets that have a range of widths & an array was a way for me to orient myself. There are simply a LOT of these in the collection & the base names had to be something the source app could serialize when processing w/as few iterations possible. I'll look at lists. My issue wrt dictionaries was any risk of lookup costs if there were 3M of these objects & diff lengths. Even a tree meant some time testing nodes rather than address sequences but I am prepared to accept I could be wrong.
    – poppycock
    Commented Feb 16, 2024 at 22:44

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.