4

TCL でハッシュのハッシュを作成して反復するにはどうすればよいですか?

次のようなデータがある場合:

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

一度に 1 つのリーフ ノード データ項目を挿入して、このようなハッシュを作成するにはどうすればよいですか。何かのようなもの:

ラッペンド foo(a)(ab) "ab1"

では、すべてのデータ要素を反復処理するにはどうすればよいでしょうか? お気に入り:

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

編集: 残念ながら、新しい 'dict' コンストラクトにアクセスできません。

4

4 に答える 4

8

Tcl 8.5+ を使用していると仮定すると、辞書が最適です。

辞書を定義するのは簡単です:

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

または、プログラムで定義します。

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

そしてそれを出力します:

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

edit : 配列ソリューション (非辞書) を別の回答に移動しました。

于 2009-08-24T18:25:14.450 に答える
7

Tcl 8.5 を使用していない場合は、配列を使用できます。配列は 1 次元ですが、キーは多次元を偽装するために使用できる任意の文字列であることに注意してください。

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

それを出力します -- 注: 辞書のキーとは異なり、配列のキーは順不同です:

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

キー (例 'b' と 'bc') が与えられている場合、次のようにして値を取得できます。

set key1 b
set key2 bc
foreach elem $foo($key1,$key2) {puts $elem}
于 2009-08-24T20:42:53.423 に答える
1

Tcl 8.5辞書の贅沢がない場合は、キー付きリストコマンドを使用して作業を完了してください。あなたはこれらの用語の1つをグーグルで検索することができます:keylget、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]"
于 2009-09-14T16:51:19.590 に答える
1

dict コマンドを使用せずに dict (キーと値のペアのリスト) を反復処理するだけの場合は、単純に foreach の素晴らしい機能を使用できます。

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

一方、dict コマンドを使用しないと、要素を 1 つずつ挿入するのは面倒です。

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

幸いなことに、dict コマンドの純粋な tcl 実装を使用できます

于 2009-09-03T08:52:36.513 に答える