Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Multiple values from NamedTuple #38834

Closed
kescobo opened this issue Dec 11, 2020 · 6 comments
Closed

[Feature Request] Multiple values from NamedTuple #38834

kescobo opened this issue Dec 11, 2020 · 6 comments

Comments

@kescobo
Copy link
Contributor

kescobo commented Dec 11, 2020

I think it would be useful to have some syntax for returning a subset of a NamedTuple as another NamedTuple, analogous to the same ability with regular Tuples.

julia> tup = (1, 2, 3)
(1, 2, 3)

julia> tup[1]
1

julia> tup[[1,2]]
(1, 2)

julia> tup[[1]]
(1,)

julia> nt = (a=1, b=2, c=3)
(a = 1, b = 2, c = 3)

julia> nt[:a]
1

julia> nt[[:a, :b]]
ERROR: MethodError: no method matching getindex(::NamedTuple{(:a, :b, :c), Tuple{Int64, Int64, Int64}}, ::Vector{Symbol})

The following works, though I don't know if it's the most efficient:

julia> get(n::NamedTuple, ntkeys) = (; (s=>n[s] for s in ntkeys)...)
get (generic function with 2 methods)

julia> get(nt, [:a,:b])
(a = 1, b = 2)

julia> get(nt, [:a])
(a = 1,)

I'm not advocating it actually be called get - I think something that worked with getindex would be ideal. NamedTupleTools.jl has a method called select that does this, but it seems like this functionality would be great to have in Base.

One counter argument is that this doesn't work with Dicts

julia> dict = Dict(pairs(nt)...)
Dict{Symbol, Int64} with 3 entries:
  :a => 1
  :b => 2
  :c => 3

julia> dict[[:a, :b]]
ERROR: KeyError: key [:a, :b] not found

But it is technically possible to have an array as a key in a Dict, but not for a NamedTuple.

I'm happy to make a PR if this idea is acceptable, and if there aren't any implications that are escaping me.

@kescobo
Copy link
Contributor Author

kescobo commented Dec 11, 2020

Another suggestions from slack helpdesk:

julia> sel = (:a, :b);

julia> NamedTuple{sel}((nt[k] for k in sel))
(a = 1, b = 2)

@JeffBezanson
Copy link
Member

The correct way to do it currently is

julia> nt = (a=1, b=2, c=3)

julia> NamedTuple{(:a, :b)}(nt)
(a = 1, b = 2)

i.e. the generator there is just redundant.

We could maybe define

@inline getindex(nt::NamedTuple, s::Tuple{Vararg{Symbol}}) = NamedTuple{s}(nt)

though this also conflicts with Dicts unfortunately.

@kescobo
Copy link
Contributor Author

kescobo commented Dec 11, 2020

though this also conflicts with Dicts unfortunately.

Do you mean conceptually or literally? Dicts aren't a subtype of NamedTuple, right?

NamedTuple{(:a, :b)}(nt) is a little clunky, but if adding the getindex method is problematic, perhaps just making it clearer in the docs so it's easier to find. I had looked here, here, and the docstring for NamedTuple. It turns out that it is in the docstring

NamedTuple{names}(nt::NamedTuple)

  Construct a named tuple by selecting fields in names (a tuple of Symbols) from another named tuple.

but I guess because this signature is so dissimilar from the types of selection syntax I'm used to, I skimmed past it.

@JeffBezanson
Copy link
Member

I guess we could add the getindex method.

@JeffreySarnoff
Copy link
Contributor

JeffreySarnoff commented Jan 10, 2021

though this also conflicts with Dicts unfortunately.

afaik The conflict is limited to Dicts with key[s] that are typed NTuple{N,Symbol}.
NamedTuples cannot have fieldnames that are typed NTuple{N,Symbol}.

I do not find the conflict all that concerning. If the desire is for conflict-free getindexing, there are two approaches that occur to me. Introduce getindicies that would require key[s] to be given as a Tuple, which would disambiguate the case of a key that is a tuple. Or use the dotted form of getindex which also presents the key[s] contained in a tuple.

@JeffBezanson
Copy link
Member

duplicate of #27021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants