# Multi layer Dict merge

**URL:** <https://discourse.julialang.org/t/multi-layer-dict-merge/27261>\
**Category:** General Usage\
**Tags:** question, dictionary, recursion, merge\
**Created:** [August 7, 2019, 11:27am UTC](https://discourse.julialang.org/t/multi-layer-dict-merge/27261 "2019-08-07T11:27:09Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![YongHee-Kim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yonghee-kim/32/5965_2.png) [@YongHee-Kim](https://discourse.julialang.org/u/YongHee-Kim)\
**Post date:** [August 7, 2019, 11:27am UTC](https://discourse.julialang.org/t/multi-layer-dict-merge/27261/1 "2019-08-07T11:27:09Z")

</div>

I was trying to merge multi-layered Dict which is…

```julia
x = [ 
 Dict("d1"=>"A1")
 Dict("d1b"=>Dict("d2a"=>"B1"))
 Dict("d1b"=>Dict("d2b"=>"C1"))]

julia>merge(x...) 
Dict{String,Any} with 2 entries:
  "d1" => "A1"
  "d1b" => Dict("d2b"=>"C1")

```

the second layer of a dictionary is being overwritten, so I could do this

```julia

julia>merge(merge, x...)
Dict{String,Any} with 2 entries:
  "d1" => "A1"
  "d1b" => Dict("d2b"=>"C1","d2a"=>"B1")

```

And I wanted to merge the third and fourth layer of a dictionary as well.  
but `merge(merge, x...)` wouldn’t work here.

```julia
x = [ Dict("d1"=>"A1")
        Dict("d1b"=>Dict("d2a"=>"B1"))
         Dict("d1b"=>Dict("d2b"=>"C1"))
          Dict("d1b"=>Dict("d2c"=>Dict("d3a"=>"D1")))
           Dict("d1b"=>Dict("d2c"=>Dict("d3b"=>"E1")))]

julia> merge(merge, x...)
Dict{String,Any} with 2 entries:
  "d1" => "A1"
  "d1b" => Dict{String,Any}("d2b"=>"C1","d2a"=>"B1","d2c"=>Dict("d3b"=>"E1"))

```

third layer `"d2c"=>Dict("d3a"=>"D1")` are being overwritten here

It would be nice if I could accomplish this while preserving beautiful julia syntax 🙂

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [August 7, 2019, 1:50pm UTC](https://discourse.julialang.org/t/multi-layer-dict-merge/27261/2 "2019-08-07T13:50:26Z")

</div>

How about

```julia
recursive_merge(x::AbstractDict...) = merge(recursive_merge, x...)

```

```julia
julia> recursive_merge(x...) # with your last x
Dict{String,Any} with 2 entries:
  "d1" => "A1"
  "d1b" => Dict{String,Any}("d2b"=>"C1","d2a"=>"B1","d2c"=>Dict("d3b"=>"E1","d3a"=>"D1"))

```

---

<div class="post-metadata">

**Author:** ![kevbonham](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kevbonham/32/216165_2.png) [@kevbonham](https://discourse.julialang.org/u/kevbonham)\
**Post date:** [August 7, 2019, 1:54pm UTC](https://discourse.julialang.org/t/multi-layer-dict-merge/27261/3 "2019-08-07T13:54:05Z")

</div>

I’m on mobile, so I’m not going to write it out, but I think your best bet might be some sort of recursive function with a loop or two. You can loop through keys with `for k in keys (mydict)`, and check if a dictionary has a key with `haskey(mydict, key)`.

Edit: oops, someone beat me to it! Better solution too 🙂

---

<div class="post-metadata">

**Author:** ![YongHee-Kim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yonghee-kim/32/5965_2.png) [@YongHee-Kim](https://discourse.julialang.org/u/YongHee-Kim)\
**Post date:** [August 7, 2019, 2:13pm UTC](https://discourse.julialang.org/t/multi-layer-dict-merge/27261/4 "2019-08-07T14:13:29Z")

</div>

wow, it works great!  
Didn’t knew varags function unwarps dictionary and It can be used such way 😆

Thank you!

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [August 7, 2019, 4:02pm UTC](https://discourse.julialang.org/t/multi-layer-dict-merge/27261/5 "2019-08-07T16:02:47Z")

</div>

> [@YongHee-Kim](#):
>
> Didn’t knew varags function unwarps dictionary

No, that’s not what’s going on; the varargs is just because the `merge` methods in Base also support merging multiple dictionaries at once, and in fact that’s the functionality you’re using by splatting the 5-element `x` vector. It may be more instructive to compare two-argument versions of `recursive_merge` and the `merge(merge, x...)` you already came up with:

```julia
recursive_merge(x1::AbstractDict, x2::AbstractDict) = merge(recursive_merge, x1, x2)
not_so_recursive_merge(x1::AbstractDict, x2::AbstractDict) = merge(merge, x1, x2)

```

I’ll let you think about the difference for a bit; as a hint, to untangle things and simplify the thought process it may be helpful to think of `merge(x1, x2)` and `merge(combine, x1, x2)` as a completely different functions (e.g., with the latter called `merge_with_combine(combine, x1, x2)`.

---

<div class="post-metadata">

**Author:** ![hhaensel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hhaensel/32/1207_2.png) [@hhaensel](https://discourse.julialang.org/u/hhaensel)\
**Post date:** [May 19, 2020, 1:57pm UTC](https://discourse.julialang.org/t/multi-layer-dict-merge/27261/6 "2020-05-19T13:57:50Z")

</div>

In case that there is duplicate key in one of the dicts, the above example of `recursive_merge` fails with

`ERROR: MethodError: no method matching recursive_merge(::String, ::String)`

If you add a second less specific method, you can even merge dictionaries with identical keys.

```julia
#recursively merge kw-dicts
recursive_merge(x::AbstractDict...) = merge(recursive_merge, x...)
# if values are not AbstractDicts, take the last definition (as does merge)
recursive_merge(x...) = x[end]

```

Here I chose to keep the last entry, because it follows the convention that has been chosen for `merge`.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [June 1, 2021, 10:52pm UTC](https://discourse.julialang.org/t/multi-layer-dict-merge/27261/7 "2021-06-01T22:52:45Z")

</div>

For anyone who found this on Google while looking for a recursive merge of JSON-like data structures, here’s a third method which allows this to work with vectors (assume them to be unordered sets)

```julia
recursive_merge(x::AbstractDict...) = merge(recursive_merge, x...)
recursive_merge(x::AbstractVector...) = cat(x...; dims=1)
recursive_merge(x...) = x[end]

```

Example:

 ![Screen Shot 2021-06-01 at 6.50.13 PM](https://global.discourse-cdn.com/julialang/original/3X/5/2/528c2e8b2cff0da22f0313a5cb6335004149d3d3.png)
