# Dict keys equality

**URL:** <https://discourse.julialang.org/t/dict-keys-equality/3986>\
**Category:** General Usage\
**Tags:** question\
**Created:** [May 30, 2017, 9:29am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986 "2017-05-30T09:29:28Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [May 30, 2017, 9:29am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/1 "2017-05-30T09:29:28Z")

</div>

Why are the `keys` of `Dict` not equal? Why do I need to actually `collect` them?

```nohighlight
julia> a = Dict(Symbol(i) => i for i = 1:5)
Dict{Symbol,Int64} with 5 entries:
  Symbol("1") => 1
  Symbol("2") => 2
  Symbol("4") => 4
  Symbol("3") => 3
  Symbol("5") => 5

julia> b = Dict(Symbol(i) => i for i = 1:5)
Dict{Symbol,Int64} with 5 entries:
  Symbol("1") => 1
  Symbol("2") => 2
  Symbol("4") => 4
  Symbol("3") => 3
  Symbol("5") => 5

julia> keys(a) == keys(b)
false

julia> collect(keys(a)) == collect(keys(b))
true

```

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 30, 2017, 9:45am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/2 "2017-05-30T09:45:30Z")

</div>

Using `@edit keys(a) == keys(b)` we can see that this falls back to `x === y` which is false because they are not the same object. Defining a method

```julia
Base.:(==)(a::Base.KeyIterator, b::Base.KeyIterator) = a.dict == b.dict

```

should do the trick. Same could be applied to `ValueIterator`. Perhaps you could make a PR?

---

<div class="post-metadata">

**Author:** ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)\
**Post date:** [May 30, 2017, 9:50am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/3 "2017-05-30T09:50:04Z")

</div>

Defining the method to be equivalent to `a.dict == b.dict` would be confusing IMHO, since you would expect it to also work when dicts are not equal. The definition should be more involved: when dicts are not equal, it should check whether all keys are equal. I’m not sure this can be done efficiently, since the order is not defined, but `isempty(symdiff(a, b))` would work.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 30, 2017, 9:51am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/4 "2017-05-30T09:51:22Z")

</div>

Yes, sorry, I was confused about what the dict contained. It is a bit more involved indeed.

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [May 30, 2017, 9:54am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/5 "2017-05-30T09:54:39Z")

</div>

Yes I’ve been thinking about this one too - I think it’s useful to see if the keys of any two `Associative`s are the same up to ordering.

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [May 30, 2017, 9:58am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/6 "2017-05-30T09:58:23Z")

</div>

My two cents are that if `collect(keys(a)) == collect(keys(b))` is true then `keys(a) == keys(b)` should also be true. I also might be missing the point.

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [May 30, 2017, 10:02am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/7 "2017-05-30T10:02:51Z")

</div>

If you call `collect`, then the order matters (so if two dictionaries had the same keys but stored internally in a different order, the keys would not be seen to be equal, while IMO opinion you usually ask this question when you just care that `haskey` returns the same for both collections, and not about the order)

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [May 30, 2017, 10:03am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/8 "2017-05-30T10:03:42Z")

</div>

So yes you are correct - but I think it should return true in a wider range of cases than that.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 30, 2017, 10:06am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/9 "2017-05-30T10:06:26Z")

</div>

`collect` replaced with `Set`?

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [May 30, 2017, 10:25am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/10 "2017-05-30T10:25:05Z")

</div>

Well, Set is just a Dict with empty values, no? So we’re back at comparing keys.

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [May 30, 2017, 10:25am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/11 "2017-05-30T10:25:28Z")

</div>

I see…! yes, I agree with you.

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [May 30, 2017, 11:42am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/12 "2017-05-30T11:42:10Z")

</div>

I thought that by definition, if a Dict has the same keys then their order must also be the same…?

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [May 30, 2017, 12:03pm UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/13 "2017-05-30T12:03:55Z")

</div>

This?

```julia

function same_keys(dicts...)
    for d1 in dicts, k1 in keys(d1), d2 in setdiff(dicts, d1)
        (k1 in keys(d2)) || return false
    end
    return true
end

d1 = Dict(:a => rand(), :b => rand())
d2 = Dict(:a => rand(), :b => rand())
d3 = Dict(:a => rand(), :b => rand())
d4 = Dict(:a => rand(), :b => rand(), :r => rand())
same_keys(d1, d2, d3, d4)

```

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [May 30, 2017, 12:26pm UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/14 "2017-05-30T12:26:27Z")

</div>

I suspect it’s faster to compare the `length`s of the dictionaries rather than testing set membership in both directions. I’d propose something like this:

```julia
Base.:(==)(a::Base.KeyIterator, b::Base.KeyIterator) = length(a)==length(b) && all(k->in(k,b), a)

```

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [May 31, 2017, 2:32am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/15 "2017-05-31T02:32:29Z")

</div>

Yep, that would be really useful.

However, note that `Dict` is just one type of `Associative` and sometimes the question will be asked is: do two `Associative`s of different types have the same set of keys? Not sure that `keys(a) == keys(b)` could ever cover all cases if some `Associative`s just store their keys as a vector or a tuple, say.

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [May 31, 2017, 6:09am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/16 "2017-05-31T06:09:34Z")

</div>

One solution would be to make all the different `KeyIterator` objects subtypes of `AbstractSet` and make sure that they all have `length`, `in`, etc. Then it would be possible to define a general method for `==(a::AbstractSet, b::AbstractSet)`, if that does not exist already.

(It might be necessary to write faster methods for special cases to get reasonable performance, but that’s a separate issue.)

---

<div class="post-metadata">

**Author:** ![fengyang.wang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fengyang.wang/32/104_2.png) [@fengyang.wang](https://discourse.julialang.org/u/fengyang.wang)\
**Post date:** [May 31, 2017, 7:32am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/17 "2017-05-31T07:32:48Z")

</div>

This makes sense to me. Why wouldn’t `keys(dict)` be an `AbstractSet`? It implements the entire (immutable) Set interface in a reasonable complexity. Sets are basically implemented as a view over the keys of a dictionary anyway.

---

<div class="post-metadata">

**Author:** ![ylxdzsw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ylxdzsw/32/925_2.png) [@ylxdzsw](https://discourse.julialang.org/u/ylxdzsw)\
**Post date:** [June 2, 2017, 8:42am UTC](https://discourse.julialang.org/t/dict-keys-equality/3986/18 "2017-06-02T08:42:02Z")

</div>

Though an edge case, this solution may not always work:

```julia
julia> Base.:(==)(a::Base.KeyIterator, b::Base.KeyIterator) = length(a)==length(b) && all(k->in(k,b), a)

julia> p = [1]
1-element Array{Int64,1}:
 1

julia> a = ObjectIdDict(p=>1, [1]=>1)
ObjectIdDict with 2 entries:
  [1] => 1
  [1] => 1

julia> b = Dict(p=>1, [2]=>1)
Dict{Array{Int64,1},Int64} with 2 entries:
  [2] => 1
  [1] => 1

julia> keys(a) == keys(b)
true

julia> keys(b) == keys(a)
false

```

We may need to better treat the equation operation if we don’t restrict the definition to `KeyIterator{Dict{T, S}}`
