tclns2

Dynamically Create Nested Lists in TCL


Using Tcl inside NS2, I am trying to create nested lists based on a total number of items. For example, I have 20 items therefore I need to create 20 lists inside an allLists {} list that I can later add certain values to using something like a puts "[lindex $allLists 0 2]". Below is my code:

for {set i 0} {$i < $val(nn)} {incr i} {
    set allClusters {
        set nodeCluster [lindex $allClusters $i] {}
    }
}
puts "$allClusters" 
puts "Node Cluster 0: [lindex $nodeCluster 0]"

My expected output would be 20 blank lists and 1 additional for nodeCluster 0:

{}
{}
{}
...
Node Cluster 0: {}

Instead I get it as a quoted item:

set nodeCluster [lindex $allClusters $i] {}

One, I do not want to set the nested lists manually because later I will have 100s of lists inside $allLists. Two, I want to eventually not create a nested list if no values will be appended to it.

How do I create nested lists for a changing value?


Solution

  • I did not fully understand the question, but from what I understood, you need to create a list of lists, with the bigger list containing 20 smaller lists. You can perhaps use something like this:

    set allClusters [list]
    set subClusters [list]
    for {set i 0} {$i < 20} {incr i} {
        lappend subClusters [list]
    }
    lappend allClusters $subClusters
    
    puts $allClusters
    # {{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}}
    

    $allClusters is a list of 20 smaller lists.

    If you then want to set a value to the smaller list at index 2, you have to extract the smaller list first, then lappend to it, then put it back:

    set subCluster [lindex $allClusters 0 2]
    lappend subCluster "test"
    lset allClusters 0 2 $subCluster
    

    You could create a proc to do the above:

    proc deepLappend {clusterName indices value} {
        upvar $clusterName cluster
        set subCluster [lindex $cluster {*}$indices]
        lappend subCluster $value
        lset cluster {*}$indices $subCluster
    }
    
    deepLappend allClusters {0 2} "test"
    deepLappend allClusters {0 2} "test"
    
    puts $allClusters
    # {{} {} {test test} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}}
    

    Though if you are creating a set of empty lists, you can try using lrepeat:

    set allClusters [list [lrepeat 20 [list]]]
    # {{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}}