The following is a few extensions to the [dict] command which I have found useful. (The '''proc-ensemble''' command is the one shown on my [fredderic's gems] page.) Of the lot shown here, the two ''get'' variants are by far the most useful. : '''dict get?''' ''dictionary key ?...? varName'' If ''key'' exists within the dictionary, then store the value in ''varName'' and return true. Otherwise, returns false and leaves the variable unchanged. : '''dict get!''' ''dictionary key ?...? default'' If ''key'' exists within the dictionary, then return it as usual. Otherwise, return the supplied ''default'' value. : '''dict set?''' ''dictName key ?...? value varName'' Sets a new ''value'' in the dictionary, but returns any existing value in the manner of '''dict get?''' as well. : '''dict set!''' ''dictName key ?...? value'' Sets a new ''value'' in the dictionary, but only if no value for that key already exists. (Not particularly useful, but it's had its moments.) : '''dict unset?''' ''dictName key ?...? varName'' Unsets a ''key'' from the dictionary, but returns any existing value in the manner of '''dict get?''' as well. : '''dict unset!''' ''dictName key ?...?'' Mostly for symmetry, this one simply doesn't error if the ''key'' does not exist. : '''dict lappend!''' ''dictName key ?...? value'' Intended primarily for dictionary keys containing lists of flags, this command won't append the given ''value'' to a key which already contains it. : '''dict multiset''' ''dictionary ?key ...? itemList key value'' Sets the specified ''key'' / ''value'' pair over each of the sub-keys listed in ''itemList''. : '''dict zip''' ''?key dictionary?'' ... Merge several dictionaries, inserting an extra level of nesting to distinguish the values from each dictionary. ---- ====== proc-ensemble ::dict { get? {args} { # dict::get to variable and return boolean if { [llength $args] < 3 } { error-args "dict get? dictionary key ?...? varName" } ::set varName [lindex $args end] ::set args [lrange $args 0 end-1] if { [llength [lindex $args 0]] % 2 == 1 } { return -level 1 -code error \ "missing value to go with key" } if { [dict exists {*}$args] } { uplevel 1 [list ::set $varName [dict get {*}$args]] return 1 } return 0 } get! {args} { # dict::get with default return value if { [llength $args] < 3 } { error-args "dict get! dictionary key ?...? default" } ::set default [lindex $args end] ::set args [lrange $args 0 end-1] if { [llength [lindex $args 0]] % 2 == 1 } { return -level 1 -code error \ "missing value to go with key" } if { [dict exists {*}$args] } { return [dict get {*}$args] } else { return $default } } set? {args} { # dict::set but return previous value if { [llength $args] < 4 } { error-args "dict set? varName key ?...? value varName" } upvar 1 [lindex $args 0] dict [lindex $args end] var ::set path [lrange $args 1 end-2] ::set valu [lindex $args end-1] if { [::info exists dict] && [dict exists $dict {*}$path] } { ::set var [dict get $dict {*}$path] ::set rc 1 } else { ::set rc 0 } dict ::set dict {*}$path $valu return $rc } set! {args} { # dict::set but only if element doesn't exist if { [llength $args] < 3 } { error-args "dict set! varName key ?...? value" } upvar 1 [lindex $args 0] var ::set args [lrange $args 1 end] if { ! [::info exists var] || ! [dict exists $var {*}[lrange $args 0 end-1]] } { dict set var {*}$args } return $var } unset? {args} { # dict::unset but returns boolean and old value if { [llength $args] < 3 } { error-args "dict unset? varName key ?...? retVar" } upvar 1 [lindex $args 0] var [lindex $args end] ret ::set args [lrange $args 1 end-1] if { [::info exists var] && [dict exists $var {*}$args] } { ::set ret [dict get $var {*}$args] dict unset var {*}$args return 1 } return 0 } unset! {args} { # dict::unset but doesn't throw error if { [llength $args] < 2 } { error-args "dict unset! varName key ?...?" } upvar 1 [lindex $args 0] var ::set args [lrange $args 1 end] if { ! [::info exists var] || ! [dict exists $var {*}$args] } return return [dict unset var {*}$args] } lappend! {args} { # dict::append but only if list element doesn't exist if { [llength $args] < 3 } { error-args "dict lappend! varName key ?...? value" } upvar 1 [lindex $args 0] var ::set value [lindex $args end] ::set args [lrange $args 1 end-1] if { [::info exists var] && [dict exists $var {*}$args] } { ::set list [dict get $var {*}$args] if { $value in $list } {return $var} lappend list $value } else { ::set list [list $value] } return [dict set var {*}$args $list] } multiset {args} { # dict::set that sets the same key/value over multiple sub-keys if { [llength $args] < 4 } { error-args "dict multiset dictionary ?key ...? itemList key value" } ::set keys [lassign [lrange $args 0 end-3] dictionary] lassign [lrange $args end-2 end] items key value # now process the multiset ::set dict [dict get $dictionary {*}$keys] foreach item $items { dict set dict $item $key $value } if { [llength $keys] == 0 } {return $dict} return [dict set dictionary {*}$keys $dict] } zip {args} { # dict::merge that adds a level inbetween if { [llength $args] % 2 == 1 } { error-args "dict zip ?key dictionary? ..." } ::set dict [list] foreach {key items} $args { dict for {name item} $items { dict set dict $name $key $item } } return $dict } } ====== <> Command