Tcl8.5からの新しいデータ型のdictについて。

リストと配列の中間みたいな。構造体みたいに扱うリストの要素に名前でアクセスできなかったり、配列をprocから返せなかったり、そういう不便なところを解消するのが使いどころな気がする。keyとvalueのペアで構成された、ただのリストに見える・・・Hashで実装されてた。配列より速いらしいが、Tclの場合リストもデータによっては配列より速い場合もあるので、list,array,dictの三つで比較してみないとなんともわからん。とりあえずはまだ8.5に移行したくないので、8.4用のライブラリをインストールして使ってみた。

コマンド早引き

dict append varName key ?value ...?keyの値の末尾にvalueを連結。
dict create ?key value ...?dictの作成。
dict exists dictionary key ?key ...?keyが存在するかどうか。
dict filter dictionary filterType ...フィルターをかけて要素を間引いて返す。
dict for {keyVar valueVar} dictionary scriptforeachみたいな。
dict get dictionary ?key key ...?keyの値を返す。
dict incr varName key ?increment?keyの値を増やす。incrと同じ。
dict info dictionarydictの内部情報を返す。
dict keys dictionary ?pattern?keyのリストを返す。
dict lappend varName key ?value ...?keyの値をリストとして要素を追加。
dict merge ?dictionary ...?複数のdictを合成して返す。
dict remove dictionary ?key ...?keyのペアを削除したdictを返す。
dict replace dictionary ?key value ...?keyをvalueで置換えたのを返す。
dict set varName key ?key ...? valuekeyにvalueをセット。
dict size dictionary要素数を返す。
dict unset varName key ?key ...?keyのペアを削除。
dict update varName key varName ?key varName ...? scriptkeyをvarNameにアサインしてコードを実行
dict values dictionary ?pattern?値のリストを返す。
dict with varName ?key ...? scriptdictの名前空間でコードを実行

基本的な使い方

set d [dict create name toyota]

で作成。必要に応じてlist型と相互変換してるので、[list name toyota]でリストを作って入れても、dictコマンドでdict型に変換するので、使う分にはキーと値のペアのlist型とdict型はあまり気にしないでよいみたいだ。
あとは普通に上の早引きを見ながらちょちょいと使ってみれば大体わかると思う。。。

set d [dict create]
dict set d name toyota
dict set d code 7203

みたいな。

ネスト

dictは入れ子にできる。これはdictがarrayと違う大きな要因の一つだと思う。

% set d [dict create a [dict create aa 0] b 1]
a {aa 0} b 1
%
% dict get $d a
aa 0
%
% dict get $d a aa
0

これはaの子のdictのaaにアクセスしてみた感じ。
もしこれが{a {b0 b1} c}みたいなリストでb1を得たいならlindex {a {b0 b1} c} 1 1みたいにするけど、キー名でアクセスできるとこが使いやすい。
dict set でもネストされたとこにアクセスして値をセットできるが、ネスト先が無い時や、dictでないとき(またはdictに変換できないペアにならない値一つの場合とか)は最初に空dictをいれなければならないようだ。
これはエラー

set d [dict create a 0 b 1]
dict set d c cc 2


こうやる。

set d [dict create a 0 b 1]
dict set d c {}
dict set d c cc 2

便利な使いどころ

arrayの代用。arrayはprocの中からそのまま返せなかったりするので、[array get a]と[array set a]などを入出力に使ったり、upvarを使ったり、グローバル変数としてアクセスするなどしていた。

# 例1 : array get/array setで入出力
proc test {alist} {
    array set arr $alist
    ....
    return [array get arr]
}
array set ga {hoge 0 fuga 1}
test [array get ga]
# 例2 : upvarで参照渡しみたいな。
proc test {alist} {
    upvar $alist arr
    ....
}
array set ga {hoge 0 fuga 1}
test ga


めんどくさいわけですよ。そこでdict。procからそのまま値を返せる。

proc test {} {
    return [dict create hoge 0 fuga 1] 
}
puts [test]

やっと人並みになった感じが・・・。つうか今のarrayを廃止して、dictで全部実装しなおした方がよいような・・・。

dict filterの練習

フィルターはkey, value, scriptの三つの種類がある。

dict filter dict key pattern
dict filter dict value pattern
dict filter dict script {keyName valueName} body
% dict filter {aa 0 ab 1 ac 2 ba 3 bb 4 bc 5} key a*
ac 2 aa 0 ab 1
% dict filter {n1 akane n2 aiko n3 ayumi n4 ai} value ai*
n2 aiko n4 ai
% dict filter {toyota 1.15 honda 3.05 nissan -0.71} script {k v} {expr $v>0}
toyota 1.15 honda 3.05

dict updateの練習

set info {name toyota code 7203}
dict update info name nameVar code codeVar {
    set nameVar [string toupper $nameVar]
    set codeVar ($codeVar)
}
puts $info
name TOYOTA code (7203)

と、まあこの場合、infoのnameがnameVarに、codeがcodeVarにアサインされて、ボディ中で色々いじって、最後にinfoに値が書き戻されるという。dict withも似たようなもんだが、dict updateは要素の中身を追加できるとこがdict withと違うようだ。

perを追加してみる例。

set info {name toyota code 7203 price 5280}
dict update info per perVar {
    set perVar 15
}
puts $info
name toyota per 15 price 5280 code 7203

あまり良い例じゃないような・・・。まあいいか。

priceを削除してみる例

set info {name toyota code 7203 price 5280}
dict update info price priceVar {
    unset priceVar
}
puts $info
name toyota code 7203

最後の書き戻しの時に、マップされた値(この場合priceVar)が無いとdictからその対応したキーが削除される。

body中でもdictにアクセスすることもできる。priceの2倍の値をprice2というキーを新しく作って入れてみる。

set info {name toyota code 7203 price 5280}
dict update info price2 price2Var {
    set price2Var [expr 2 * [dict get $info price]]
}
puts $info
price2 10560 name toyota price 5280 code 7203

dict withの練習

BASICのwithみたいなイメージ?

set info {name toyota code 7203 price 5280}
dict with info {
    puts name=$name
    puts code=$code
    puts price=$price
} 

みたいな。書き換えても反映される。

dict updateと同じように、対応した名前が見つからない時は要素が削除される。

set info {name toyota code 7203 price 5280}
dict with info {
   unset name
}
puts $info
price 5280 code 7203

速度比較

コメントをどーぞ


リンク


CategoryTclTk


|New|Edit|Freeze|Diff|History|Attach|Copy|Rename|
Last-modified: 2010-05-16 (Sun) 01:00:28
HTML convert time: 0.015 sec.