# Reordering NamedTuples

Dear All,

I want to ask, if anyone knows about fast (ideally typed stable) method to reorder named tuples. A
MWE would look like

``````(a = 1, b = 2, c = 3)

julia> y = (c = 1, b = 2, a = 1)
(c = 1, b = 2, a = 1)

julia> map(+, x, y)
ERROR: ArgumentError: Named tuple names do not match.
Stacktrace:
 map(f::Function, nt::NamedTuple{(:a, :b, :c), Tuple{Int64, Int64, Int64}}, nts::NamedTuple{(:c, :b, :a), Tuple{Int64, Int64, Int64}})
@ Base ./namedtuple.jl:195
 top-level scope
@ REPL:1
``````

and I am looking for a function, call it `align`, such that

``````map(+, x, align(x,y)
``````

would return a NamedTuple

``````(a = 2, b = 4, c = 4)
``````

Thanks a lot for help in advance.

Tomas

Is this enough?

Input:

``````x = (a = 1, b = 2, c = 3)
y = (c = 1, b = 2, a = 1)
z = NamedTuple(k => x[k] + y[k] for k in keys(x))
``````

Output:

``````(a = 2, b = 4, c = 4)
``````

I am all about type stability.

On the end, I did this.

``````function _reorder_nt(x::NamedTuple{NT,<:Any}, y::NamedTuple{NT,<:Any}) where {NT}
y
end

function _reorder_nt(x::NamedTuple{NX,<:Any}, y::NamedTuple{NY,<:Any}) where {NX,NY}
NamedTuple{NX}(map(k -> getfield(y, k), NX))
end
``````

well, it’s looks like `mergewith` for named tuples.
https://docs.julialang.org/en/v1/base/collections/#Base.mergewith

I made `mergewith` for that purpose and most code taken from the `julia/base/namedtuple.jl`. you could get here (somewhat long to paste and it’s not tested a lot)

Just as with regular tuples, `NamedTuple`s have each type of its elements as a type parameter, i.e. the types of the elements are part of the type.

As such, an arbitrary reordering with the reordering not being known to the compiler will not be type stable.

I think this is pretty simple and efficient:

``````julia> nt1 = (; a = 1, b = 2)
(a = 1, b = 2)

julia> nt2 = (; b = 3, a = 4)
(b = 3, a = 4)

julia> NamedTuple{keys(nt1)}(nt2)
(a = 4, b = 3)

julia> @code_warntype NamedTuple{keys(nt1)}(nt2)
MethodInstance for (NamedTuple{(:a, :b)})(::NamedTuple{(:b, :a), Tuple{Int64, Int64}})
from (NamedTuple{names})(nt::NamedTuple) where names in Base at namedtuple.jl:99
Static Parameters
names = (:a, :b)
Arguments
#self#::Type{NamedTuple{(:a, :b)}}
nt::NamedTuple{(:b, :a), Tuple{Int64, Int64}}
Body::NamedTuple{(:a, :b), Tuple{Int64, Int64}}
1 ─ %1 = Core.apply_type(Base.NamedTuple, \$(Expr(:static_parameter, 1)), Tuple{Int64, Int64})::Core.Const(NamedTuple{(:a, :b), Tuple{Int64, Int64}})
│   %2 = Base.getfield(nt, 2)::Int64
│   %3 = Base.getfield(nt, 1)::Int64
│   %4 = %new(%1, %2, %3)::NamedTuple{(:a, :b), Tuple{Int64, Int64}}
└──      return %4
``````

It’s implemented in Base with a generated function.

5 Likes

I think that will be horrible for performance if you see a lot of distinct `NamedTuple`s (i.e. arbitrary reordering) Not really sure where one would get arbitrarily ordered NamedTuples from, but I agree if that’s the case, then a data structure with the order encoded in the type domain is the wrong data structure (independently of how you try to align them).

Edit: but the function I suggested is type stable: if the compiler knows the types of the input NamesTuples (and thus the order), then the type of the output is known to the compiler too.

4 Likes

and long (because other wise combinations would soon be enumerated). But in that case, OP should use

Yep, because you’re lifting everything to the type domain via that generated function - if `nt1` were only known at runtime, it’d be unstable imo (or at least if the names (and their order?) of that tuple were only known at runtime).

Right, but what I mean is the function

``````align(nt1, nt2) = NamedTuple{keys(nt1)}(nt2)
``````

is still type stable-- if the types of the inputs are known, the types of the outputs are known. If the types of the inputs are not known, then yes the compiler won’t know the types of the outputs here. So the overall procedure of {stuff producing dynamically typed `nt1` + using this `align`} would be not type stable, but the problem is coming in before the `align`.

1 Like

This exactly what I was looking for. Thanks a lot.

1 Like