How to slice a NamedTuple?

How to?

julia> (;a=10, b=20, c=30)[2:end]
ERROR: MethodError: no method matching getindex(::@NamedTuple{a::Int64, b::Int64, c::Int64}, ::UnitRange{Int64})
# Desired: (;b=20, c=30)

I think there’s not a super natural operation implemented because it’s type unstable. But you could do

julia> slice(nt, inds) = NamedTuple{keys(nt)[inds]}(nt)
slice (generic function with 1 method)

julia> nt = (;a=10, b=20, c=30)
(a = 10, b = 20, c = 30)

julia> slice(nt, 2:lastindex(nt))
(b = 20, c = 30)

If you wanted the end syntax to work here also, you could use iend from GitHub - JuliaArrays/EndpointRanges.jl: Julia package for doing arithmetic on endpoints in array indexing.

2 Likes

Or even simpler, nt[keys(nt)[inds]].
NamedTuples are indexable with multiple symbols, but not with multiple integers…

3 Likes

ah this is nicer too since you can use end:

julia> nt[keys(nt)[2:end]]
(b = 20, c = 30)

I guess if we support indexing by symbols dynamically then there’s not really a good reason to not support integers.

3 Likes

Btw, if you really need to drop just the first/last element and happen to already be using Accessors, then

julia> using Accessors

julia> @delete first(nt)
(b = 20, c = 30)

is readable and type-stable :slight_smile:

Also, using rest():

julia> nt = (;a=10, b=20, c=30)
(a = 10, b = 20, c = 30)

julia> Base.rest(nt, 2)
(b = 20, c = 30)
2 Likes

Nice as well, but note that it’s not type-stable, and relies on internals (meaning of the 2nd argument is not specified).