Home > Mobile >  How to dynamically create array and assign value in TCL
How to dynamically create array and assign value in TCL

Time:02-04

I want to create array dynamically and assign value to it. e.g.

set num 0
foreach i {1 2 3} {
    set count$i(sp) {$num}
    incr num
    set count$i(ep) [expr $num 1]
}

CodePudding user response:

When I ran your sample code, this error comes up:

can't read "i(sp)": variable isn't array

which is because the $i(sp) part of count$i(sp) looks like a reference to an existing array i.

You'll want to isolate $i from (sp) with curly brackets:

set num 0
foreach i {1 2 3} {
    set count${i}(sp) {$num}
    incr num
    set count${i}(ep) [expr $num 1]
}

which creates three arrays:

tcl8.6.8> parray count1
count1(ep) = 2
count1(sp) = $num
tcl8.6.8> parray count2
count2(ep) = 3
count2(sp) = $num
tcl8.6.8> parray count3
count3(ep) = 4
count3(sp) = $num

Note above that curly brackets around $num use the literal string $num. You'll want to remove those curly brackets:

set num 0
foreach i {1 2 3} {
    set count${i}(sp) $num
    incr num
    set count${i}(ep) [expr $num 1]
}
tcl8.6.8> parray count1
count1(ep) = 2
count1(sp) = 0
tcl8.6.8> parray count2
count2(ep) = 3
count2(sp) = 1
tcl8.6.8> parray count3
count3(ep) = 4
count3(sp) = 2

However, please explain exactly what you mean by "dynamically creating a Tcl array". Do you really want three separate arrays or could you have one array with more names, like this:

set num 0
foreach i {1 2 3} {
    set count($i,sp) $num
    incr num
    set count($i,ep) [expr $num 1]
}
tcl8.6.8> parray count
count(1,ep) = 2
count(1,sp) = 0
count(2,ep) = 3
count(2,sp) = 1
count(3,ep) = 4
count(3,sp) = 2

CodePudding user response:

You might enjoy using a dict instead of an array:

set count {}
set num 0

foreach i {1 2 3} {
  dict set count $i sp $num
  incr num
  dict set count $i ep [expr {$num   1}]
}

set count               ;# -> 1 {sp 0 ep 2} 2 {sp 1 ep 3} 3 {sp 2 ep 4}
dict get $count 3 ep    ;# -> 4

CodePudding user response:

If you can avoid using a dynamic variable name like that, do so; they're often more trouble than they're worth. (You can use “composite” element names like $i,sp instead.) Otherwise — perhaps because of other code that accesses the array — the simplest way of handling them is to use upvar to make an alias to the variable with a fixed name. In particular, upvar 0 makes an alias to a variable in the same scope:

set num 0
foreach i {1 2 3} {
    upvar 0 count$i ary
    set ary(sp) {$num}
    incr num
    set ary(ep) [expr $num 1]
}

The only problem with upvar 0 is that you can't really undo it; that's why you almost always only use it within a procedure so the aliasing goes away naturally when the procedure exits.

Variable aliases are extremely efficient within the context of a procedure, substantially more so than using compound variable names in multiple places.


Also, {$num} looks suspicious. It's not wrong code in that it has a correct interpretation, but might not do what you expect and is often indicative of a problem, as $num isn't substituted. You might prefer [list $num].

  •  Tags:  
  • Related