2009-08-24 6 views
4

Wie kann ich einen Hash der Hashes in TCL erstellen und durchlaufen?Wie kann ich einen Hash der Hashes in TCL erstellen und durchlaufen?

Wenn ich Daten wie:

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 } 
    } 
} 

Wie erstelle ich eine solche Hash zu einem Zeitpunkt ein Endknoten-Datenelement eingefügt wird. Etwas wie:

lappend foo (a) (ab) "ab1"

Dann wie iterieren ich alle Datenelemente über? wie:

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: Leider habe ich keinen Zugriff auf die neuere 'dict' konstruieren.

+0

Ich teile meine Antwort auf die nicht-dict-Lösung zu markieren. –

Antwort

7

Wenn Sie Tcl 8.5 nicht verwenden, können Sie Arrays verwenden. Beachten Sie, dass Arrays eindimensional sind, aber der Schlüssel ist eine beliebige Zeichenfolge, die zu fälschen Mehrdimensionalität verwendet werden können:

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

und gibt es - beachten Sie: Array-Schlüssel, anders als Dictionary-Schlüssel sind ungeordnete:

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

Wenn Sie die Schlüssel gegeben sind (zB ‚b‘ und ‚bc‘) können Sie den Wert erhalten so:

set key1 b 
set key2 bc 
foreach elem $foo($key1,$key2) {puts $elem} 
8

Angenommen, Sie Tcl verwenden 8.5+, Wörterbücher sind der Weg zu gehen:

definieren das Wörterbuch einfach gemacht:

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 } 
    } 
} 

Oder definieren es programmatisch:

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

Und geben Sie es aus:

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

bearbeiten: Die Array-Lösung (nicht diktiert) wurde in eine separate Antwort verschoben.

+0

Ich habe keinen Zugriff auf das 'dict' Konstrukt .. danke für die Antwort. –

1

Wenn Sie nur durch eine dict iterieren wollen (das ist einfach ein Schlüssel-Wert-Paar-Liste) w hne der dict Befehl dann können Sie einfach die awesomeness von foreach verwenden:

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" 
    } 
    } 
} 

auf der anderen Seite, die Elemente einer nach dem anderen ist schmerzhaft, ohne die dict Befehl Einfügen:

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 :-(

zum Glück können Sie verwenden eine pure-tcl-implementation des dict-befehls: forward-compatible dict

1

Wenn Sie nicht den Luxus des Tcl 8.5-Wörterbuchs haben, verwenden Sie die Befehle der gedrückten Liste, um die Arbeit zu erledigen. Sie können nach einem dieser Begriffe google, keylset.

package require Tclx 

# Create the nested structure 
catch {unset foo} 
foreach key1 {a b c} { 
    foreach key2 {a b c} { 
     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 {a b c} { 
    foreach key2 {a b c} { 
     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's list index is 0 based 
puts "foo\\c\\cb\\1 = [lindex [keylget foo c.cb] 0]"