# Merging dictionaries ensuring they are disjoint

**URL:** <https://discourse.julialang.org/t/merging-dictionaries-ensuring-they-are-disjoint/115859>\
**Category:** General Usage\
**Tags:** question\
**Created:** [June 19, 2024, 1:12pm UTC](https://discourse.julialang.org/t/merging-dictionaries-ensuring-they-are-disjoint/115859 "2024-06-19T13:12:37Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 19, 2024, 1:12pm UTC](https://discourse.julialang.org/t/merging-dictionaries-ensuring-they-are-disjoint/115859/1 "2024-06-19T13:12:37Z")

</div>

I am merging some dictionaries that come from a computation and I want to ensure that they are disjoint.

A quick way of doing it is `mergewith`, eg

```julia
D1 = Dict(:a => 1, :b => 2)
D2 = Dict(:a => 4, :c => 3)
mergewith((v...) -> error("multiple values $v for some key"), D1, D2)

```

but that has the disadvantage that I cannot report the offending key to the user.

I am just curious if there is a way to do this **with built-in functions** that I missed.

> **(of course coding this is trivial)**
>
> ```julia
> function merge_disjoint(dict1::AbstractDict{K1,V1},
> dict2::AbstractDict{K2,V2}) where {K1,V1,K2,V2}
> K = promote_type(K1, K2)
> V = promote_type(V1, V2)
> result = Dict{K,V}(dict1)
> for (k, v) in pairs(dict2)
> if haskey(result, k)
> throw(ArgumentError("key $k present in multiple dictionaries, cannot merge"))
> else
> result[k] = v
> end
> end
> result
> end
> 
> ```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [June 19, 2024, 2:59pm UTC](https://discourse.julialang.org/t/merging-dictionaries-ensuring-they-are-disjoint/115859/2 "2024-06-19T14:59:19Z")

</div>

> [@Tamas\_Papp](#):
>
> but that has the disadvantage that I cannot report the offending key to the user.

```julia
mergewith((v...) -> error("duplicated keys $(intersect(keys(D1), keys(D2)))"), D1, D2)

```

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [June 19, 2024, 6:28pm UTC](https://discourse.julialang.org/t/merging-dictionaries-ensuring-they-are-disjoint/115859/3 "2024-06-19T18:28:20Z")

</div>

Another route:

```julia
using StatsBase

D1 = Dict(:a => 1, :b => 2)
D2 = Dict(:a => 4, :c => 3)

keys(filter(>(1)∘last,addcounts!(countmap(keys(D1)), keys(D2))))

```

giving:

```julia
KeySet for a Dict{Symbol, Int64} with 1 entry. Keys:
  a:

```

(without the initial `keys(...)` the amount of repetition can also be obtained)

If there are more dictionaries, then a `foldl` with `addcounts!` and an `init` kwarg set to `countmap` should be possible.

Note, this method doesn’t short-circuit, so if that is necessary the other methods can work.

UPDATE: Another method which does short-circuit:

```julia
let k::keytype(D1), s = Set{keytype(D1)}(), i=0
    for outer k in Iterators.flatten([keys(D1), keys(D2)])
        i += 1
        k in s && break
        push!(s, k)
    end
    i == length(s) ? nothing : k
end

```

This method tries to be resource efficient, and can work for any number of dictionaries by changing the argument of `flatten` appropriate. The `let`’s value is nothing if no repetition or the first repeating element if there is one.

ADDENDUM: This isn’t exactly the OP’s request, as the dictionaries are not merged. So, oops, sorry, but still an interesting problem.

POST ADDENDUM: To fix the issue in the Addendum, here is a method which returns the desired dictionary but also is resource efficient (at this point benchmarking should be done):

```julia
let s = false, r = Dict{keytype(D1), valtype(D1)}()
    for e in Iterators.flatten([D1,D2])
        mergewith!((v...)->(s = true; last(v)), r, Base.ImmutableDict(e))
        s && error("duplicate key $e")
    end
    r
end

```
