diff --git a/NEWS.md b/NEWS.md index f663bbc5c0ea7..d0d6bcf6ef340 100644 --- a/NEWS.md +++ b/NEWS.md @@ -33,6 +33,7 @@ New library functions * New `findall(pattern, string)` method where `pattern` is a string or regex ([#31834]). * `istaskfailed` is now documented and exported, like its siblings `istaskdone` and `istaskstarted` ([#32300]). * `RefArray` and `RefValue` objects now accept index `CartesianIndex()` in `getindex` and `setindex!` ([#32653]) +* `NamedTuple`s may now be subsetted with `getindex` ([#27021], [#32662]) Standard library changes ------------------------ diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 67eaaa9efe941..af253339217b1 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -102,7 +102,16 @@ iterate(t::NamedTuple, iter=1) = iter > nfields(t) ? nothing : (getfield(t, iter firstindex(t::NamedTuple) = 1 lastindex(t::NamedTuple) = nfields(t) getindex(t::NamedTuple, i::Int) = getfield(t, i) +getindex(t::NamedTuple, i::Integer) = t[to_index(i)] getindex(t::NamedTuple, i::Symbol) = getfield(t, i) +function getindex(t::NamedTuple, v::AbstractVector{Bool}) + length(t) == length(v) || throw(BoundsError(t, v)) + return t[to_index(v)] +end +getindex(t::NamedTuple, v::AbstractVector) = (; map(v) do i + k = i isa Symbol ? i : keys(t)[i] + return k => t[i] + end...) indexed_iterate(t::NamedTuple, i::Int, state=1) = (getfield(t, i), i+1) isempty(::NamedTuple{()}) = true isempty(::NamedTuple) = false diff --git a/test/namedtuple.jl b/test/namedtuple.jl index 82e711d625cbc..b2bc200fb07bb 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -21,6 +21,19 @@ @test (a=3,)[:a] == 3 @test (x=4, y=5, z=6).y == 5 @test (x=4, y=5, z=6).z == 6 +@test (x=4, y=5, z=6)[1:1] == (x=4,) +@test (x=4, y=5, z=6)[1:2] == (x=4, y=5) +@test (x=4, y=5, z=6)[[1,3]] == (x=4, z=6) +@test (x=4, y=5, z=6)[[:x,:y]] == (x=4, y=5) +@test (x=4, y=5, z=6)[[:x,2]] == (x=4, y=5) +@test (x=4, y=5, z=6)[[true, true, false]] == (x=4, y=5) +@test (x=4, y=5, z=6)[[true, true, true]] == (x=4, y=5, z=6) +@test (x=4, y=5, z=6)[[false, false, false]] == NamedTuple() +@test (x=4, y=5, z=6)[Int[]] == NamedTuple() +@test_throws BoundsError (x=4, y=5, z=6)[[true, true]] +@test_throws ArgumentError (x=4, y=5, z=6)[true] +@test (x=4, y=5, z=6)[0x01] == (x=4, y=5, z=6)[Int16(1)] == 4 +@test (x=4, y=5, z=6)[0x01:0x01] == (x=4, y=5, z=6)[[Int16(1)]] == (x=4,) @test_throws ErrorException (x=4, y=5, z=6).a @test_throws BoundsError (a=2,)[0] @test_throws BoundsError (a=2,)[2]