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

***コマンド早引き [#ddbf8502]
,''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%%% script''',foreachみたいな。
,''dict get'' '''%%%dictionary%%% ?key key ...?'''  ,keyの値を返す。
,''dict incr'' '''varName key ?increment?'''       ,keyの値を増やす。incrと同じ。
,''dict info'' '''%%%dictionary%%%'''              ,dictの内部情報を返す。
,''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 ...? value'''          ,keyにvalueをセット。
,''dict size'' '''%%%dictionary%%%'''                    ,要素数を返す。
,''dict unset'' '''varName key ?key ...?'''              ,keyのペアを削除。
,''dict update'' '''varName key varName ?key varName ...? script''',keyをvarNameにアサインしてコードを実行
,''dict values'' '''%%%dictionary%%% ?pattern?'''        ,値のリストを返す。
,''dict with'' '''varName ?key ...? script''',dictの名前空間でコードを実行
-varNameはdict変数の名前で、%%%dictionary%%%は値そのものなので注意。lappend, append, set, unset, incr以外は値。tclのコマンドと同じか。
-get, exists, set, unsetでkeyを複数指定するのはネストされたdictへのアクセス。

***基本的な使い方 [#t94be0c2]
 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
みたいな。

***ネスト [#k85d37b6]
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

***便利な使いどころ [#g9d659f7]
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の練習 [#o7417ebd]
フィルターは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の練習 [#sc98224a]
 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の練習 [#r4514666]
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

***速度比較 [#g63ab74c]

***コメントをどーぞ [#d011b37e]
- dictはそのままファイルに保存できるのもいいですね。ただ、ソースの見た目が分かりにくいのでネストしないものは相変わらずarrayでやってます。 -- [[ゆーすけ]] &new{2008-07-05 (土) 22:49:32};
- array はそれ自体の配列がとれなかった。それをdictに期待したのだが...残念、便利になったのはそのままreturnできるくらいか... -- [[パケモン]] &new{2010-05-14 (金) 13:17:39};
- array getもあるし、dictはリスト互換だし、何を言いたいのかわからない。 -- [[reddog]] &new{2010-05-16 (日) 00:58:57};

#comment

***リンク [#x5748fb9]
-http://www.tcl.tk/man/tcl8.5/TclCmd/dict.htm
-http://www.tcl.tk/cgi-bin/tct/tip/111.html
-http://www.tcl.tk/cgi-bin/tct/tip/212.html
-[[dict:http://wiki.tcl.tk/5042]]
-[[Dict VS Array Speed:http://wiki.tcl.tk/13826]]
-http://pascal.scheffers.net/software/ (Tcl8.4用のdictライブラリ)
-http://svn.scheffers.net/misc/dict/ (上の作者さんのリポジトリ)
----
[[CategoryTclTk]]

|New|Edit|Diff|History|Attach|Copy|Rename|
HTML convert time: 0.002 sec.