dict(n)
π NAME π
dict β the Tcl built-in for manipulating dictionaries. That's it, that's the whole name line, and yes it's dict(n) in the manual because we are fancy like that. π
β¨ SYNOPSIS β¨
dict option arg ?arg ...?
π«Ά DESCRIPTION π«Ά
Okay so bestie, dict performs one of several operations on dictionary values β or on variables that hold dictionary values, which is a whole thing (go read the DICTIONARY VALUES section below for the full description of what a dictionary value even is) β and which operation you get depends entirely on option.
The legal options are listed below, and they may be abbreviated, which is lowkey the most convenient glow-up in the whole command. Slay.
dict appenddictionaryVariable key ?string ...?β this appends the given string (or strings) to the value that the givenkeymaps to, inside the dictionary value living in the given variable, and then writes the resulting dictionary value right back into that variable. Keys that don't exist yet? Treated as if they map to an empty string, no drama. The updated dictionary value gets returned. And heads up: ifdictionaryVariableindicates an element that does not exist of an array that has a default value set, that default value will be used as the value of the dictionary prior to the appending operation. π«Άdict create?key value ...?β returns a brand new dictionary containing each of the key/value mappings you listed as arguments. Keys and values alternate, each key followed by its associated value. It's giving friendship bracelet, but make it data. πdict existsdictionaryValue key ?key ...?β returns a boolean value saying whether the given key (or path of keys threading through a set of nested dictionaries) exists in the given dictionary value. It returns a true value exactly whendict geton that path will succeed. No cap, that's the rule.dict filterdictionaryValue filterType arg ?arg ...?β takes a dictionary value and returns a new dictionary containing just those key/value pairs that match the specified filter type (which may be abbreviated). The supported filter types are:dict filterdictionaryValue key ?globPattern ...?β thekeyrule only matches those key/value pairs whose keys match any of the given patterns, in the style ofstring match.dict filterdictionaryValue script {keyVariable valueVariable} scriptβ thescriptrule tests for matching by assigning the key to thekeyVariableand the value to thevalueVariable, then evaluating the given script, which should result in a boolean value. The key/value pair only gets included in the result of thedict filterwhen a true value is returned. Note that the first argument after the rule selection word is a two-element list. If the script returns with a condition ofTCL_BREAK, no further key/value pairs are considered for inclusion in the resulting dictionary, and a condition ofTCL_CONTINUEis equivalent to a false result. The key/value pairs are tested in the order in which the keys were inserted into the dictionary.dict filterdictionaryValue value ?globPattern ...?β thevaluerule only matches those key/value pairs whose values match any of the given patterns, in the style ofstring match.
dict for{keyVariable valueVariable} dictionaryValue bodyβ this command takes three arguments. First, a two-element list of variable names (for the key and the value respectively of each mapping in the dictionary). Second, the dictionary value to iterate across. Third, a script to be evaluated for each mapping with the key and value variables set appropriately, in the manner offoreach. The result of the command is an empty string. If any evaluation of thebodygenerates aTCL_BREAKresult, no further pairs from the dictionary will be iterated over and thedict forcommand will terminate successfully immediately. If any evaluation of thebodygenerates aTCL_CONTINUEresult, that shall be treated exactly like a normalTCL_OKresult. The order of iteration is the order in which the keys were inserted into the dictionary. πdict getdictionaryValue ?key ...?β given a dictionary value (first argument) and a key (second argument), this retrieves the value for that key. Where several keys are supplied, the behaviour of the command shall be as if the result ofdict get $dictVal $keywas passed as the first argument todict getwith the remaining arguments as second (and possibly subsequent) arguments. This facilitates lookups in nested dictionaries. For example, these two commands are equivalent:
dict get $dict foo bar spong
dict get [dict get [dict get $dict foo] bar] spong
If no keys are provided, dict get will return a list containing pairs of elements in a manner similar to array get. That is, the first element of each pair would be the key and the second element would be the value for that key.
It is an error to attempt to retrieve a value for a key that is not present in the dictionary. π¨
dict getdefdictionaryValue ?key ...? key defaultdict getwithdefaultdictionaryValue ?key ...? key default
This behaves the same as dict get (with at least one key argument), returning the value that the key path maps to in the dictionary dictionaryValue, except that instead of producing an error because the key (or one of the keys on the key path) is absent, it returns the default argument instead. π
Note that there must always be at least one key provided, and that dict getdef and dict getwithdefault are aliases for each other. Twins. Iconic.
dict incrdictionaryVariable key ?increment?β this adds the given increment value (an integer that defaults to1if not specified) to the value that the givenkeymaps to in the dictionary value contained in the given variable, writing the resulting dictionary value back to that variable. Non-existent keys are treated as if they map to0. It is an error to increment a value for an existing key if that value is not an integer. The updated dictionary value is returned. IfdictionaryVariableindicates an element that does not exist of an array that has a default value set, the default value will be used as the value of the dictionary prior to the incrementing operation. β¨dict infodictionaryValueβ this returns information (intended for display to people, so like, for your eyeballs) about the given dictionary, though the format of this data is dependent on the implementation of the dictionary. For dictionaries that are implemented by hash tables, it is expected that this will return the string produced byTcl_HashStats, similar toarray statistics.dict keysdictionaryValue ?globPattern?β returns a list of all keys in the given dictionary value. If a pattern is supplied, only those keys that match it (according to the rules ofstring match) will be returned. The returned keys will be in the order that they were inserted into the dictionary. πdict lappenddictionaryVariable key ?value ...?β this appends the given items to the list value that the givenkeymaps to in the dictionary value contained in the given variable, writing the resulting dictionary value back to that variable. Non-existent keys are treated as if they map to an empty list, and it is legal for there to be no items to append to the list. It is an error for the value that the key maps to to not be representable as a list. The updated dictionary value is returned. IfdictionaryVariableindicates an element that does not exist of an array that has a default value set, the default value will be used as the value of the dictionary prior to the list-appending operation.dict map{keyVariable valueVariable} dictionaryValue bodyβ this command applies a transformation to each element of a dictionary, returning a new dictionary. It takes three arguments: the first is a two-element list of variable names (for the key and value respectively of each mapping in the dictionary), the second is the dictionary value to iterate across, and the third is a script to be evaluated for each mapping with the key and value variables set appropriately, in the manner oflmap. In an iteration where the evaluated script completes normally (TCL_OK, as opposed to an error, etc.) the result of the script is put into an accumulator dictionary using the key that is the current contents of thekeyVariablevariable at that point. The result of thedict mapcommand is the accumulator dictionary after all keys have been iterated over.
If the evaluation of the body for any particular step generates a break, no further pairs from the dictionary will be iterated over and the dict map command will terminate successfully immediately. If the evaluation of the body for a particular step generates a continue result, the current iteration is aborted and the accumulator dictionary is not modified. The order of iteration is the natural order of the dictionary (typically the order in which the keys were added to the dictionary; the order is the same as that used in dict for). π¦
dict merge?dictionaryValue ...?β returns a dictionary that contains the contents of each of thedictionaryValuearguments. Where two (or more) dictionaries contain a mapping for the same key, the resulting dictionary maps that key to the value according to the last dictionary on the command line containing a mapping for that key. Last one wins, that's the rule. πdict removedictionaryValue ?key ...?β returns a new dictionary that is a copy of the old one passed in as the first argument, except without mappings for each of the keys listed. It is legal for there to be no keys to remove, and it is also legal for any of the keys to be removed to not be present in the input dictionary in the first place. Very forgiving, we love that. πΈ
π¦ dict replace π¦
Bestie, this one returns a brand new dictionary that's a copy of the old one you handed in as the first argument β except with some values swapped out or some extra key/value pairs dropped in. π
- It is legal to call this with no key/value pairs at all.
- It is illegal to call this with a key but no value. (Don't do it, she will not be happy. π)
β¨ dict set β¨
Takes the name of a variable holding a dictionary value and places an updated dictionary value into that variable β one that maps the given key to the given value. When you pass multiple keys, this operation creates or updates a chain of nested dictionaries. The updated dictionary value gets returned to you. π
And if dictionaryVariable points at an element that does not exist yet of an array that has a default value set, that default value is what gets used as the value of the dictionary before the insert/update happens. π«Ά
πΈ dict size πΈ
Returns the number of key/value mappings in the dictionary value you passed. That's it, that's the whole vibe check. Literally just the count. β¨
π
dict unset π
This is the companion to dict set β she's the one who takes things away. She takes the name of a variable holding a dictionary value and places an updated dictionary value into that variable, one that does not contain a mapping for the given key. π
When multiple keys show up, that describes a path through nested dictionaries to the mapping you want removed. Some rules, no cap:
- At least one key must be specified.
- The last key on the key-path need not exist.
- All other components on the path must exist.
The updated dictionary value gets returned. And same as her sister: if dictionaryVariable points at an element that does not exist of an array that has a default value set, the default value is used as the value of the dictionary before the remove operation runs. π¦
π dict update π
Okay so this one is iconic but also a little feral. She executes the Tcl script in body with the value for each key (as found by reading the dictionary value in dictionaryVariable) mapped to the variable varName. You can have multiple key varName pairs. If a key doesn't have a mapping, that's the same as an unset varName. π
When body terminates, any changes you made to the varNames get reflected back into the dictionary inside dictionaryVariable β even if the result of body is an error or some other kind of exceptional exit. The one exception (lol) is if dictionaryVariable itself becomes unreadable, in which case all updates are silently discarded. π
The result of dict update is (unless some kind of error occurs) the result of evaluating body.
And if dictionaryVariable indicates an element that does not exist of an array that has a default value set, that default value will be used as the value of the dictionary prior to the update operation. π
Each varName is mapped in the scope enclosing the dict update. It is recommended that this command only be used in a local scope β a procedure, a lambda term for apply, or a method. Because of that, the variables set by dict update will keep existing after the command finishes (unless you explicitly unset them). π
Heads up bestie: the mapping of values to variables does not use traces. Changes todictionaryVariable's contents only happen whenbodyterminates. No mid-script surprises, no tea. π
π dict values π
Returns a list of all the values in the given dictionary value. If you supply a pattern, only those values that match it get returned β matched according to the rules of string match. π₯
And here's the cute part: the returned values come in the order that the keys associated with those values were inserted into the dictionary. Order-preserving, always. β¨
π§ dict with π§
Execute the Tcl script in body with the value for each key in dictionaryVariable mapped β in a manner similar to dict update β to a variable with the same name. π
Where one or more keys are given, those indicate a chain of nested dictionaries, with the innermost dictionary being the one opened out for the execution of body. As with dict update, making dictionaryVariable unreadable means the updates to the dictionary get discarded β and the same thing happens if the contents of dictionaryVariable get adjusted so that the chain of dictionaries no longer exists. π
The result of dict with is (unless some kind of error occurs) the result of the evaluation of body.
If dictionaryVariable indicates an element that does not exist of an array that has a default value set, the default value will be used as the value of the dictionary prior to the updating operation. π«Ά
The variables are mapped in the scope enclosing the dict with; it is recommended that this command only be used in a local scope (a procedure, a lambda term for apply, or a method). Because of this, the variables set by dict with will continue to exist after the command finishes (unless explicitly unset). π
Same note as before, babe: the mapping of values to variables does not use traces. Changes todictionaryVariable's contents only happen whenbodyterminates. πΈ
And now the part that lowkey bites: if dictionaryVariable contains a value that is not a dictionary at the point when body terminates β which can very easily happen if the name is the same as any of the keys in dictionary β then an error occurs at that point. So this command is not recommended for use when the keys in the dictionary are expected to clash with the dictionaryVariable name itself. π
Where the contained key does map to a dictionary, the net effect is to combine that inner dictionary into the outer dictionary. There's an illustration of this in the EXAMPLES below. π¦
π DICTIONARY VALUES π
Dictionaries are values that contain an efficient, order-preserving mapping from arbitrary keys to arbitrary values. Every key in the dictionary maps to a single value. β¨
They have a textual format that is exactly that of any list with an even number of elements, with each mapping in the dictionary being represented as two items in the list. π
When a command takes a dictionary and produces a new dictionary based on it β either by returning it, or by writing it back into the variable that the starting dictionary was read from β the new dictionary will have the same order of keys, modulo any deleted keys, with new keys added on to the end. πΈ
When a string is interpreted as a dictionary and it would otherwise have duplicate keys, only the last value for a particular key is used; the others are ignored. Which means apple banana and apple carrot apple banana are equivalent dictionaries β they just have different string representations. π
Operations that derive a new dictionary from an old one (e.g. updates like dict set and dict unset) preserve the order of keys in the dictionary. The exceptions to this are:
- any new keys they add, which are appended to the sequence, and
- any keys that are removed, which are excised from the order.
No cap, that's just how she runs. π
π§ͺ EXAMPLES π§ͺ
okay bestie, this is the part where it all clicks. grab a snack, we're doing real code. π
π± Basic dictionary usage
starter pack: a dict that maps file extensions to descriptions.
# Make a dictionary to map extensions to descriptions
set filetypes [dict create .txt "Text File" .tcl "Tcl File"]
# Add/update the dictionary
dict set filetypes .tcl "Tcl Script"
dict set filetypes .tm "Tcl Module"
dict set filetypes .gif "GIF Image"
dict set filetypes .png "PNG Image"
# Simple read from the dictionary
set ext ".tcl"
set desc [dict get $filetypes $ext]
puts "$ext is for a $desc"
# Somewhat more complex, with existence test
foreach filename [glob *] {
set ext [file extension $filename]
if {[dict exists $filetypes $ext]} {
puts "$filename is a [dict get $filetypes $ext]"
}
}
see how dict set is doing double duty? that's the "Add/update" energy π
and the last chunk is the existence test β dict exists peeks first before dict get commits. very demure, very mindful.
πͺ Constructing and using nested dictionaries
now we go β¨layeredβ¨. employees inside employees. it's giving organizational chart.
# Data for one employee
dict set employeeInfo 12345-A forenames "Joe"
dict set employeeInfo 12345-A surname "Schmoe"
dict set employeeInfo 12345-A street "147 Short Street"
dict set employeeInfo 12345-A city "Springfield"
dict set employeeInfo 12345-A phone "555-1234"
# Data for another employee
dict set employeeInfo 98372-J forenames "Anne"
dict set employeeInfo 98372-J surname "Other"
dict set employeeInfo 98372-J street "32995 Oakdale Way"
dict set employeeInfo 98372-J city "Springfield"
dict set employeeInfo 98372-J phone "555-8765"
# The above data probably ought to come from a database...
# Print out some employee info
set i 0
puts "There are [dict size $employeeInfo] employees"
dict for {id info} $employeeInfo {
puts "Employee #[incr i]: $id"
dict with info {
puts " Name: $forenames $surname"
puts " Address: $street, $city"
puts " Telephone: $phone"
}
}
# Another way to iterate and pick out names...
foreach id [dict keys $employeeInfo] {
puts "Hello, [dict get $employeeInfo $id forenames]!"
}
lowkey the comment in there says the data probably ought to come from a database. it's not wrong. π
and then a second way to iterate, because dict for and foreach over dict keys are both valid main character choices. no notes. π
π A localizable version of string toupper
this one is so smart it hurts. we're building a string toupper that knows about locales.
# Set up the basic C locale
set capital [dict create C [dict create]]
foreach c [split {abcdefghijklmnopqrstuvwxyz} ""] {
dict set capital C $c [string toupper $c]
}
# English locales can luckily share the "C" locale
dict set capital en [dict get $capital C]
dict set capital en_US [dict get $capital C]
dict set capital en_GB [dict get $capital C]
# ... and so on for other supported languages ...
# Now get the mapping for the current locale and use it.
set upperCaseMap [dict get $capital $env(LANG)]
set upperCase [string map $upperCaseMap $string]
english locales get to share the "C" locale, lucky them, and the mapping for the current locale comes straight out of $env(LANG). then string map does the rest. slay. β¨
π Showing the detail of dict with
okay this one is the deep lore. watch what dict with does to a variable inside a proc:
proc sumDictionary {varName} {
upvar 1 $varName vbl
foreach key [dict keys $vbl] {
# Manufacture an entry in the subdictionary
dict set vbl $key total 0
# Add the values and remove the old
dict with vbl $key {
set total [expr {$x + $y + $z}]
unset x y z
}
}
puts "last total was $total, for key $key"
}
set myDict {
a {x 1 y 2 z 3}
b {x 6 y 5 z 4}
}
sumDictionary myDict
# prints: last total was 15, for key b
puts "dictionary is now \"$myDict\""
# prints: dictionary is now "a {total 6} b {total 15}"
so it manufactures a total 0 entry in each subdictionary, adds up the values, then unset x y z clears out the old keys. the dictionary ends up holding just the totals. chef's kiss. π
π₯ When dict with is used with a key that clashes with the name of the dictionary variable
yes, this is a real situation and yes, it's chaos. look:
set foo {foo {a b} bar 2 baz 3}
dict with foo {}
puts $foo
# prints: a b foo {a b} bar 2 baz 3
the key foo inside the dictionary is named the same thing as the variable foo, and that's what you get. iykyk. π
π SEE ALSO
go read your sisters, they're all iconic in their own way:
π KEYWORDS
dictionary, create, update, lookup, iterate, filter, map
and that's a wrap on dict(n) fr fr π this whole page is the Tcl 8.5 edition of the dict(n) manual page β that's the source, that's the version, and that's the page name, all bundled up in the little footer like a bow. π go build something nested and gorgeous. π¦
π¦ where this page comes from
- alpine 3.23: tcl9-doc 9.0.3-r0 Β· TCL
- alpine 3.24: tcl9-doc 9.0.3-r2 Β· TCL
- fedora 43: tcl-doc 1:9.0.2-1.fc43 Β· TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause
- fedora 44: tcl-doc 1:9.0.2-1.fc44 Β· TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause
- nixos 26.05: tcl 9.0.3
- nixpkgs unstable: tcl 9.1.0
- Copyright (c) 2003 Donal K. Fellows
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms