DefaultDict and DefaultOrderedDict

DefaultDict and DefaultOrderedDict

A DefaultDict allows specification of a default value to return when a requested key is not in a dictionary.

While the implementation is slightly different, a DefaultDict can be thought to provide a normal Dict with a default value. A DefaultOrderedDict does the same for an OrderedDict.


DefaultDict(default, kv)    # create a DefaultDict with a default value or function,
                            # optionally wrapping an existing dictionary
                            # or array of key-value pairs

DefaultDict{KeyType, ValueType}(default)   # create a DefaultDict with Dict type (KeyType,ValueType)

DefaultOrderedDict(default, kv)     # create a DefaultOrderedDict with a default value or function,
                                    # optionally wrapping an existing dictionary
                                    # or array of key-value pairs

DefaultOrderedDict{KeyType, ValueType}(default) # create a DefaultOrderedDict with Dict type (KeyType,ValueType)

All constructors also take a passkey::Bool=false keyword argument which determines whether to pass along the key argument when calling the default function. It has no effect when the key is just a value.

Examples using DefaultDict:

julia> dd = DefaultDict(1)               # create an (Any=>Any) DefaultDict with a default value of 1
DefaultDict{Any, Any, Int64}()
julia> dd = DefaultDict{AbstractString, Int}(0)  # create a (AbstractString=>Int) DefaultDict with a default value of 0
DefaultDict{AbstractString, Int64, Int64}()
julia> d = Dict('a'=>1, 'b'=>2)
Dict{Char, Int64} with 2 entries:
  'a' => 1
  'b' => 2

julia> dd = DefaultDict(0, d)            # provide a default value to an existing dictionary
DefaultDict{Char, Int64, Int64} with 2 entries:
  'a' => 1
  'b' => 2

julia> d['c']  # should raise a KeyError because 'c' key doesn't exist
ERROR: KeyError: key 'c' not found

julia> dd['c']
julia> dd = DefaultOrderedDict(time)     # call time() to provide the default value for an OrderedDict
DefaultOrderedDict{Any, Any, typeof(time)}()

julia> dd = DefaultDict(Dict)            # Create a dictionary of dictionaries - Dict() is called to provide the default value
DefaultDict{Any, Any, UnionAll}()

julia> dd = DefaultDict(()->myfunc())    # call function myfunc to provide the default value
DefaultDict{Any, Any, Main.var"ex-DataStructures".var"#1#2"}()

These all create the same default dict

julia> dd = DefaultDict{AbstractString, Vector{Int}}(() -> Vector{Int}())
DefaultDict{AbstractString, Vector{Int64}, Main.var"ex-DataStructures".var"#3#4"}()
julia> dd = DefaultDict{AbstractString, Vector{Int}}(() -> Int[])
DefaultDict{AbstractString, Vector{Int64}, Main.var"ex-DataStructures".var"#5#6"}()
julia> dd = DefaultDict{AbstractString, Vector{Int}}(Vector{Int})
DefaultDict{AbstractString, Vector{Int64}, DataType}()

julia> push!(dd["A"], 1)
1-element Vector{Int64}:

julia> push!(dd["B"], 2)
1-element Vector{Int64}:

julia> dd
DefaultDict{AbstractString, Vector{Int64}, DataType} with 2 entries:
  "B" => [2]
  "A" => [1]

Create a Dictionary of type AbstractString=>DefaultDict{AbstractString, Int}, where the default of the inner set of DefaultDicts is zero

julia> dd = DefaultDict{AbstractString, DefaultDict}(() -> DefaultDict{AbstractString,Int}(0))
DefaultDict{AbstractString, DefaultDict, Main.var"ex-DataStructures".var"#7#8"}()

Use DefaultDict to cache an expensive function call, i.e., memoize

julia> dd = DefaultDict{AbstractString, Int}(passkey=true) do key
           len = length(key)
           return len
DefaultDict{AbstractString, Int64, Main.var"ex-DataStructures".var"#9#10"}()

julia> dd["hi"]  # slow

julia> dd["ho"]  # slow

julia> dd["hi"]  # fast

Note that in the second-last example, we need to use a function to create each new DefaultDict. If we forget, we will end up using the sameDefaultDict for all default values:

julia> dd = DefaultDict{AbstractString, DefaultDict}(DefaultDict{AbstractString,Int}(0));

julia> dd["a"]
DefaultDict{AbstractString, Int64, Int64}()

julia> dd["b"]["a"] = 1

julia> dd["a"]
DefaultDict{AbstractString, Int64, Int64} with 1 entry:
  "a" => 1