Is there a simple way to make a named tuple from a Dict{Symbol, T}
?
There should be an easier way, but this works:
julia> NamedTuple{tuple(keys(di)...), Tuple{typeof.(collect(values(di)))...,}}((values(di)...,))
(a = 1, b = 5.6)```
dictkeys(d::Dict) = (collect(keys(d))...,)
dictvalues(d::Dict) = (collect(values(d))...,)
namedtuple(d::Dict{Symbol,T}) where {T} =
NamedTuple{dictkeys(d)}(dictvalues(d))
dictionary = Dict(:a => 5, :b => 6, :c => 7)
Dict{Symbol,Int64} with 3 entries:
:a => 5
:b => 6
:c => 7
namedtuple(dictionary)
(a = 5, b = 6, c = 7)
dictionary = Dict(:a => 5, :b => 6.0, :c => "7")
Dict{Symbol,Any} with 3 entries:
:a => 5
:b => 6.0
:c => "7"
namedtuple(dictionary)
(a = 5, b = 6.0, c = "7")
Thanks @mauro3 and @JeffreySarnoff for the replies, it would be nice of you to make a PR!
Is there nowadays a more convenient way to turn a dict into a named tuple?
julia> d = Dict(:a => 1, :b => 2)
Dict{Symbol,Int64} with 2 entries:
:a => 1
:b => 2
julia> NamedTuple{Tuple(keys(d))}(values(d))
(a = 1, b = 2)
Probably touching internal detail, but…
((; kw...) -> kw.data)(; d...)
also works.
AFAIU values(kw)
is the public accessor for kw.data
(to turn the keyword iterator into a NamedTuple
).
Tada:
julia> (; Dict(:a => 5, :b => 6, :c => 7)...)
(a = 5, b = 6, c = 7)
(Edit: note, that this already worked in Julia 0.7 when NamedTuples first appeared. Sometimes it just takes a bit longer to find the best solution…)
Ran into the inverse of this problem, so thought it might be helpful (at least not harmful) to post a solution for that here:
julia> nt = (a = 5, b = 6, c = 7)
(a = 5, b = 6, c = 7)
julia> Dict(pairs(nt))
Dict{Symbol,Int64} with 3 entries:
:a => 5
:b => 6
:c => 7
I think it would be nice if @mauro3’s solution were to appear explicitly in the documentation somewhere, and it might also be nice if there were some sort of namedtuple
function, analogous to tuple
which would probably make this functionality much easier to find.
NamedTupleTools.jl exports namedtuple
. I’d welcome issues that request additional features and be happier still with targeted PRs.
Ran into this again and just wanted to point out that the solution here seems incredibly slow
julia> @btime (;d...)
967.857 ns (13 allocations: 928 bytes)
(a = 1, b = 2)
compare that to the inverse
julia> @btime Dict(pairs(nt))
208.054 ns (7 allocations: 704 bytes)
Dict{Symbol,Int64} with 2 entries:
:a => 1
:b => 2
Anyone know of any way of speeding this up?
@Tamas_Papp solution seems twice as fast than (; d...)
. But given that this is type-unstable code, it’s maybe not so suprising that it’s slow?
And how to make a named tuple from a dictionary, when dictionary keys are of type String
?
The proposed methods do not work in such a case.
if using NamedTupleTools.jl
is ok:
julia> using NamedTupleTools
julia> adict = Dict("astr" => 5, "bstr" => 'b');
julia> namedtuple(Symbol.(keys(adict)), values(adict))
(bstr = 'b', astr = 5)
julia> typeof(ans)
NamedTuple{(:bstr, :astr),Tuple{Char,Int64}}
julia> d = Dict(["a" => 1, "b" => 2])
Dict{String,Int64} with 2 entries:
"b" => 2
"a" => 1
julia> NamedTuple{Tuple(Symbol.(keys(d)))}(values(d))
(b = 2, a = 1)
Note that of course since a Dict
not sorted, ordering is not guaranteed.
Thank you @Tamas_Papp. It worked.
This produces me an error:
MethodError: no method matching namedtuple(::Array{Symbol,1}, ::Base.ValueIterator{Dict{String,Any}})
(I am using Julia 1.0.3)
Perhaps there should be a NamedTuple constructor taking a Dict and vice versa as this seems to pop up regularly. What do you think?