How to recursively update the values of a nested dictionary?

Let’s say I have a nested dictionary like :

a_nested_dict = Dict("a"=>1,"b"=>Dict("c"=>2,"d"=>[Dict("e"=>2),Dict("f"=>3)]),"g"=>[1,"h"])

How do I override individual values, using a function like:

function override_nested_dict!(nested_dict,override_elements)
    for o_element in override_elements
        ....
    end
end

Such to produce :

a_nested_dict["a"]    = 10
a_nested_dict["g"][2] = "l"
a_nested_dict["b"]["d"][2] = Dict("i"=>4) 

In particular I don’t know the data structure of override_elements… vector of pairs of tuples as key and values?

This one for example doesn’t work:

a_nested_dict = Dict("a"=>1,"b"=>Dict("c"=>2,"d"=>[Dict("e"=>2),Dict("f"=>3)]),"g"=>[1,"h"])

function override_nested_dict!(nested_dict,override_elements)
    for o_element in override_elements
        nested_dict[o_element[1]...] = o_element[2]
    end
end

override_nested_dict!(a_nested_dict,["a"=>10,("g",2)=>"l",("b","d",2)=>Dict("i"=>4)])

Your override specifications are pairs of either a key and a value, or a Tuple of keys and a value. Your base case is when the first of the pair is not a tuple, set the key/value pair in the Dict. If the first is a tuple, then extract the first element from the tuple, use it to look up an inner Dict, then recursively do the same with the remaining elements of the Tuple and the inner Dict until you have a single element left in the Tuple. Then follow the base case.

Thanks, this seems to work:

julia> function override_nested_dict!(nested_dict,override_elements)
           for o_element in override_elements
               td = nested_dict
               o_ks = o_element[1]; o_v = o_element[2];
               (typeof(o_ks) <: Tuple) || (o_ks = (o_ks,))
               for (ik,k) in enumerate(o_ks)
                   k in keys(td) || error("Override error: Key $k not found in container $td")
                   ik == length(o_ks) ?  (td[k] = o_v)  :  (td = td[k]) 
               end
           end
       end
override_nested_dict! (generic function with 1 method)

julia> a_nested_dict     = Dict("a"=>1,"b"=>Dict("c"=>2,"d"=>[Dict("e"=>2),Dict("f"=>3)]),"g"=>[1,"h"])
Dict{String, Any} with 3 entries:
  "g" => Any[1, "h"]
  "b" => Dict{String, Any}("c"=>2, "d"=>[Dict("e"=>2), Dict("f"=>3)])
  "a" => 1

julia> override_elements = ["a"=>10,("g",2)=>"l",("b","d",2)=>Dict("i"=>4)]
3-element Vector{Pair{Any, Any}}:
           "a" => 10
      ("g", 2) => "l"
 ("b", "d", 2) => Dict("i" => 4)

julia> override_nested_dict!(a_nested_dict,override_elements)

julia> a_nested_dict
Dict{String, Any} with 3 entries:
  "g" => Any[1, "l"]
  "b" => Dict

julia> override_elements2 = ["z"=>20]
1-element Vector{Pair{String, Int64}}:
 "z" => 20

julia> override_nested_dict!(a_nested_dict,override_elements2)
ERROR: Override error: Key z not found in container Dict{String, Any}("g" => Any[1, "l"], "b" => Dict{String, Any}("c" => 2, "d" => [Dict("e" => 2), Dict("i" => 4)]), "a" => 10)
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] override_nested_dict!(nested_dict::Dict{String, Any}, override_elements::Vector{Pair{String, Int64}})
   @ Main ./REPL[19]:7
 [3] top-level scope
   @ REPL[25]:1