How to create and iterate over hash hashes in TCL?

How to create and iterate over hash hashes in TCL?

If I have data such as:

foo = { a => { aa => { aa1 aa2 aa3 } ab => { ab1 ab2 ab3 } ac => { ac1 ac2 ac3 } } b => { ba => { ba1 ba2 ba3 } bb => { bb1 bb2 bb3 } bc => { bc1 bc2 bc3 } } c => { ca => { ca1 ca2 ca3 } cb => { cb1 cb2 cb3 } cc => { cc1 cc2 cc3 } } } 

How to create such a hash by inserting one leaf-node data item at a time. Sort of:

lappend foo (a) (ab) "ab1"

Then how do I iterate over all data items? as:

 foreach key in foo { foreach sub_key in foo($key) { foreach elem in foo($key)($sub_key) { puts "foo\($key\)\($sub_key\) is $elem" } } } 

Edit: Unfortunately, I do not have access to the new "dict" construct.

+4
source share
4 answers

If you are not using Tcl 8.5, you can use arrays. Note that arrays are one-dimensional, but the key is an arbitrary string that can be used to fake multidimensionality:

 array set foo {} foreach first {abc} { foreach second {abc} { foreach third {1 2 3} { lappend foo($first,$first$second) "$first$second$third" } } } parray data 

and output it - note: array keys, unlike dictionary keys, are unordered:

 foreach key [array names foo] { foreach elem $foo($key) { puts "$key\t$elem" } } 

If you are given the keys (example "b" and "bc"), you can get the value this way:

 set key1 b set key2 bc foreach elem $foo($key1,$key2) {puts $elem} 
+7
source

Assuming you are using Tcl 8.5+, dictionaries are the way to go:

Defining a dictionary is simple:

 set foo { a { aa { aa1 aa2 aa3 } ab { ab1 ab2 ab3 } ac { ac1 ac2 ac3 } } b { ba { ba1 ba2 ba3 } bb { bb1 bb2 bb3 } bc { bc1 bc2 bc3 } } c { ca { ca1 ca2 ca3 } cb { cb1 cb2 cb3 } cc { cc1 cc2 cc3 } } } 

Or define it programmatically:

 set foo [dict create] foreach first {abc} { dict update foo $first subdict { foreach second {abc} { foreach third {1 2 3} { dict lappend subdict "$first$second" "$first$second$third" } } } } 

And print it:

 dict for {key1 subdict} $foo { dict for {key2 list} $subdict { foreach elem $list { puts "$key1\t$key2\t$elem" } } } 

edit : moved the array solution (non-tactical) to a separate answer.

+8
source

If you just want to iterate through a dict (which is just a list of key pairs and values) without the dict command, you can just use the foreach awesomeness:

 set foo { a { aa { aa1 aa2 aa3 } ab { ab1 ab2 ab3 } ac { ac1 ac2 ac3 } } b { ba { ba1 ba2 ba3 } bb { bb1 bb2 bb3 } bc { bc1 bc2 bc3 } } c { ca { ca1 ca2 ca3 } cb { cb1 cb2 cb3 } cc { cc1 cc2 cc3 } } } foreach {key value} $foo { foreach {sub_key sub_value} $value { foreach elem $sub_value { puts "foo\($key\)\($sub_key\) is $elem" } } } 

on the other hand, inserting elements one at a time is painful without the dict command:

 set foo {} lappend foo a {} set a_index [lsearch $foo a] set a_value_index [expr {$a_index+1}] set a_value [lindex $foo $a_value_index] lappend a_value aa {} lset foo $a_value_index $a_value # it is now too painful for me to continue :-( 

Fortunately, you can use the implementation of the dict-tcl command: direct-link formatting

+1
source

If you do not have the luxury of a Tcl 8.5 dictionary, use the key list commands to complete the task. You can use Google for one of these conditions: keylget, keylset.

 package require Tclx # Create the nested structure catch {unset foo} foreach key1 {abc} { foreach key2 {abc} { catch {unset element} foreach key3 {1 2 3} { lappend element "$key1$key2$key3" } keylset foo $key1.$key1$key2 $element } } # Access the nested structure foreach key1 {abc} { foreach key2 {abc} { set elementList [keylget foo $key1.$key1$key2] foreach element $elementList { puts "foo\\$key1\\$key1$key2\\$key3 = $element" } } } # # Access examples # # Access a block of data puts "foo\\a = [keylget foo a]" # Access a nested block of data puts "foo\\b\\ba = [keylget foo b.ba]" # Access an individual element, remember that Tcl list index is 0 based puts "foo\\c\\cb\\1 = [lindex [keylget foo c.cb] 0]" 
+1
source

All Articles