# Check equality of two NamedTuples with order of the fields ignored

**URL:** <https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177>\
**Category:** General Usage\
**Created:** [January 11, 2021, 8:11pm UTC](https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177 "2021-01-11T20:11:19Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Norman](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@Norman](https://discourse.julialang.org/u/Norman)\
**Post date:** [January 11, 2021, 8:11pm UTC](https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177/1 "2021-01-11T20:11:19Z")

</div>

Suppose I have the following two instances of `NamedTuple`.

```julia
julia> a = (x=1, y=2)
(x = 1, y = 2)

julia> b = (y=2, x=1)
(y = 2, x = 1)

julia> a == b
false

```

What would be the best approach to test whether `a` and `b` contain the same key-value pairs while ignoring the order of the pairs? (So, I want something that returns `true` for comparing `a` and `b`.)

Thanks!

---

<div class="post-metadata">

**Author:** ![zweiglimmergneis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zweiglimmergneis/32/7892_2.png) [@zweiglimmergneis](https://discourse.julialang.org/u/zweiglimmergneis)\
**Post date:** [January 11, 2021, 8:22pm UTC](https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177/2 "2021-01-11T20:22:57Z")

</div>

```julia
julia> a = (x=1, y=2)
(x = 1, y = 2)

julia> b = (y=2, x=1)
(y = 2, x = 1)

julia> ntd(t) = Dict(zip(keys(t), values(t)))
ntd (generic function with 1 method)

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

```

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [January 11, 2021, 8:24pm UTC](https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177/3 "2021-01-11T20:24:51Z")

</div>

```julia
sortednames(nt::NamedTuple{N,T}) where {N,T} =
  Tuple(sort([N...]))

sortednt(nt::NamedTuple) =
  NamedTuple{sortednames(nt)}(nt)

sortednt(a) == sortednt(b)

```

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [January 11, 2021, 8:26pm UTC](https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177/4 "2021-01-11T20:26:33Z")

</div>

```julia
julia> all(k->getfield(a,k) == getfield(b,k), keys(a))
true

```

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [January 11, 2021, 8:31pm UTC](https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177/5 "2021-01-11T20:31:36Z")

</div>

> [@jling](#):
>
> ` all(k->getfield(a,k) == getfield(b,k), keys(a))`

works nicely where

```julia
length(a) == length(allnames(a,b))
# and
allnames(a,b) = 
  Tuple(union(fieldnames(typeof(a)), fieldnames(typeof(b)))) 

```

```julia
≊(x::NamedTuple{N,T}, y::NamedTuple{N2,T2}) where {N,T,N2,T2} =
  length(N) === length(union(N,N2)) &&
  all(k->getfield(x,k) == getfield(y,k), keys(x))

a = (x=1, y=2)
b = (y=2, x=1)

a ≊ b # true

```

---

<div class="post-metadata">

**Author:** ![o314](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/o314/32/252_2.png) [@o314](https://discourse.julialang.org/u/o314)\
**Post date:** [May 3, 2022, 5:09am UTC](https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177/6 "2022-05-03T05:09:15Z")

</div>

Those solution do not seem to handle recursive namedtuple, eg.

```julia
aa = (qux = (quuux = 4, quux = 3), foo = (bar = 1, baz = 2))
bb = (foo = (bar = 1, baz = 2), qux = (quuux = 4, quux = 3))

```

This is more of a bug in Base IMO. (may need a `@pure sort(::Tuple)` to dispatch statically)

---

<div class="post-metadata">

**Author:** ![o314](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/o314/32/252_2.png) [@o314](https://discourse.julialang.org/u/o314)\
**Post date:** [March 20, 2023, 5:34am UTC](https://discourse.julialang.org/t/check-equality-of-two-namedtuples-with-order-of-the-fields-ignored/53177/7 "2023-03-20T05:34:53Z")

</div>

_Fix of improper previous counterexample_

```julia
≊(x::NamedTuple{N,T}, y::NamedTuple{N2,T2}) where {N,T,N2,T2} =
  length(N) === length(union(N,N2)) &&
  all(k->getfield(x,k) == getfield(y,k), keys(x))

using Test
aa = (; foo=(bar=1, baz=2), qux=(quux=3, quuux=4))
bb = (; qux=(quuux=4, quux=3), foo=(baz=2, bar=1))
@test_broken aa ≊ bb

```

Let’s consider

```julia
Base.isapprox(x::NamedTuple{N,T}, y::NamedTuple{N2,T2}) where {N,T,N2,T2} =
    length(N) === length(union(N,N2)) &&
    all(keys(x)) do k
        isapprox(getfield(x,k), getfield(y,k))
    end

using Test
aa = (; foo=(bar=1, baz=2), qux=(quux=3, quuux=4))
bb = (; qux=(quuux=4, quux=3), foo=(baz=2, bar=1))
@test aa ≈ bb

# may be too much side effect
aa = (; foo=(bar=(1+1e-8), baz=2), qux=(quux=3, quuux=4))
bb = (; qux=(quuux=4, quux=3), foo=(baz=2, bar=(1+1e-9)))
@test aa ≈ bb

```

This may work / or not, considering wheter if we intend to recursively compare approximatively or not

Still a badly defined semantic from base IMO . Accepting eq upon perms is orthogonal to num tolerance
