Is there any function like similar
which creates a struct
inhering the names and types of a NamedTuple
?
MEW:
nt = (a = 1, b ="Hello")
#some function like
MyStruct = similar(nt)
#`similar` would create this:
struct MyStruct
a::Int64
b::String
end
My question is because you can easily convert a SubDataFrame into a NamedTuple. So, retrieving some data and putting it into a model can be easily done through a NamedTuple. However, there doesn’t seem to be an easy way to move from a SubDataFrame to a struct
, unless you repeat the name of each variable and the type of each variable (which is long and prone to error if you have 20 variables).
Many thanks
-
Don’t overload similar
on types you don’t own. Define a constructor instead
-
One thing you can do is use the @with_kw
macro
@with_kw struct MyStruct
a::Int64
b::String
end
MyStruct(; nt...)
1 Like
The name similar
was just an example. But, in any case, I’m actually asking for the other way of the conversion: going from a NamedTuple
to a struct
.
Yes, my example gives you that.
Thanks, my point is that I want to avoid defining the struct
. So, I was wondering if there’s a function foo
where you can do
nt = (a = 1, b ="Hello")
MyStruct = foo(nt)
where MyStruct
gives you a struct
identifying the names and types from nt
.
Put differently, I’m trying to avoid the need to write:
Base.@kwdef struct MyStruct
a::Int64
b::String
end
by using the functino foo
that figures out the names and types.
The main purpose I would imagine for making a struct
defined based on a NamedTuple
would be in order to have your own type for dispatch without pirating functions on NamedTuple
.
For this, I’ll instead propose you make a thin wrapper over NamedTuple
. For an immutable structure, this is all you need for the wrapper approach:
struct MyStruct{NT<:NamedTuple}
nt::NT
end
Base.getproperty(x::MyStruct,y::Symbol) = Base.getproperty(getfield(x,:nt),y)
# now test it
x = MyStruct((;a=1,b="two"))
x.b # can access via the fieldnames of the NamedTuple
Note that (with this definition of getproperty
) the only way to access the nt
field of MyStruct
is via an explicit call to getfield
(ie, x.nt
will look for a nt
field within the NamedTuple instead).
There will be all sorts of stumbling blocks if you want to define a standalone struct based on an instance of a NamedTuple
. It’s literally possible, but will be based on eval
and will have horrible performance even once you do get it “working”. It will also likely cause lots of world age errors when you try to use it.
4 Likes
Thanks!! this is what I was looking for
You can also just dispatch on NamedTuple (no need for a Struct) if you will be defining all your own functions. Here are two methods I use.
# Define the function to accept keyword arguments.
# Splat a named tuple to call it.
# Keyword argument order doesn't matter since they are named.
# `c...` will slurp up any unused elements of the named tuple.
function f(; b, a, c...)
println(a+1)
println(reverse(b))
end
# Define the function to accept normal positional arguments.
# Add a method which deconstructs the named tuple and calls the main method.
function g(a, b)
println(a+2)
println(uppercase(b))
end
g(nt::NamedTuple) = g(nt.a, nt.b)
julia> nt = (a=1, b="Hello", c=:extra1, d=:extra2)
(a = 1, b = "Hello", c = :extra1, d = :extra2)
julia> f(; nt...)
2
olleH
julia> g(nt)
3
HELLO
1 Like