# How to create a struct from a dict

**URL:** <https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550>\
**Category:** General Usage\
**Tags:** question, dictionary, struct\
**Created:** [July 27, 2024, 4:41pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550 "2024-07-27T16:41:14Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [July 27, 2024, 4:41pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550/1 "2024-07-27T16:41:15Z")

</div>

I have a Dict from parsing a JSON message, and want to convert it into a struct.

This works:

```julia
using StaticArrays

const MyFloat = Float64

sys_state_dict = Dict(:time => 0,
    :t_sim => 0,
    :sys_state => 0,
    :e_mech => 0,
    :orient => [0.530989, 0.466959, -0.466959, -0.530989],
    :elevation => 1.2426,
    :azimuth => 0,
    :l_tether => 150,
    :v_reelout => 0,
    :force => 559.847,
    :depower => 0.25,
    :steering => 0,
    :heading => 0,
    :course => 0,
    :v_app => 12.5799,
    :vel_kite => [0, 0, 0],
    :X => Union{Float64, Int64}[0, 8.90221, 17.5546, 25.9174, 33.9673, 41.687, 49.0618, 49.2317, 50.7465, 50.4513, 50.4513],
    :Y => Union{Float64, Int64}[0, 0, 0, 0, 0, 0, 0, 0, 0, 2.84247, -2.84247],
    :Z => Union{Float64, Int64}[0, 23.41, 46.9136, 70.5217, 94.2383, 118.064, 142.0, 147.029, 149.031, 146.739, 146.739]
)

P = 11
mutable struct SysState{P}
    "time since start of simulation in seconds"
    time::Float64
    "time needed for one simulation timestep"
    t_sim::Float64
    "state of system state control"
    sys_state::Int16
    "mechanical energy [Wh]"
    e_mech::Float64
    "orientation of the kite (quaternion, order w,x,y,z)"
    orient::MVector{4, Float32}
    "elevation angle in radians"
    elevation::MyFloat
    "azimuth angle in radians"
    azimuth::MyFloat
    "tether length [m]"
    l_tether::MyFloat
    "reel out velocity [m/s]"
    v_reelout::MyFloat
    "tether force [N]"
    force::MyFloat
    "depower settings [0..1]"
    depower::MyFloat
    "steering settings [-1..1]"
    steering::MyFloat
    "heading angle in radian"
    heading::MyFloat
    "course angle in radian"
    course::MyFloat
    "norm of apparent wind speed [m/s]"
    v_app::MyFloat
    "velocity vector of the kite"
    vel_kite::MVector{3, MyFloat}
    "vector of particle positions in x"
    X::MVector{P, MyFloat}
    "vector of particle positions in y"
    Y::MVector{P, MyFloat}
    "vector of particle positions in z"
    Z::MVector{P, MyFloat}
end 

function sys_state_dict2struct(sys_state_dict)
    SysState{P}(sys_state_dict[:time],
        sys_state_dict[:t_sim],
        sys_state_dict[:sys_state],
        sys_state_dict[:e_mech],
        sys_state_dict[:orient],
        sys_state_dict[:elevation],
        sys_state_dict[:azimuth],
        sys_state_dict[:l_tether],
        sys_state_dict[:v_reelout],
        sys_state_dict[:force],
        sys_state_dict[:depower],
        sys_state_dict[:steering],
        sys_state_dict[:heading],
        sys_state_dict[:course],
        sys_state_dict[:v_app],
        sys_state_dict[:vel_kite],
        sys_state_dict[:X],
        sys_state_dict[:Y],
        sys_state_dict[:Z]
    )
end

sys_state_dict2struct(sys_state_dict)

```

But it is error prone, because if I make a change to the struct I also have to make a manual change to the function `sys_state_dict2struct()`.

How can I avoid that?

Not working:

```julia
using StaticArrays, StructTypes, JSON3

const MyFloat = Float64

sys_state_dict = Dict(:time => 0,
    :t_sim => 0,
    :sys_state => 0,
    :e_mech => 0,
    :orient => [0.530989, 0.466959, -0.466959, -0.530989],
    :elevation => 1.2426,
    :azimuth => 0,
    :l_tether => 150,
    :v_reelout => 0,
    :force => 559.847,
    :depower => 0.25,
    :steering => 0,
    :heading => 0,
    :course => 0,
    :v_app => 12.5799,
    :vel_kite => [0, 0, 0],
    :X => Union{Float64, Int64}[0, 8.90221, 17.5546, 25.9174, 33.9673, 41.687, 49.0618, 49.2317, 50.7465, 50.4513, 50.4513],
    :Y => Union{Float64, Int64}[0, 0, 0, 0, 0, 0, 0, 0, 0, 2.84247, -2.84247],
    :Z => Union{Float64, Int64}[0, 23.41, 46.9136, 70.5217, 94.2383, 118.064, 142.0, 147.029, 149.031, 146.739, 146.739]
)

P = 11
mutable struct SysState{P}
    "time since start of simulation in seconds"
    time::Float64
    "time needed for one simulation timestep"
    t_sim::Float64
    "state of system state control"
    sys_state::Int16
    "mechanical energy [Wh]"
    e_mech::Float64
    "orientation of the kite (quaternion, order w,x,y,z)"
    orient::MVector{4, Float32}
    "elevation angle in radians"
    elevation::MyFloat
    "azimuth angle in radians"
    azimuth::MyFloat
    "tether length [m]"
    l_tether::MyFloat
    "reel out velocity [m/s]"
    v_reelout::MyFloat
    "tether force [N]"
    force::MyFloat
    "depower settings [0..1]"
    depower::MyFloat
    "steering settings [-1..1]"
    steering::MyFloat
    "heading angle in radian"
    heading::MyFloat
    "course angle in radian"
    course::MyFloat
    "norm of apparent wind speed [m/s]"
    v_app::MyFloat
    "velocity vector of the kite"
    vel_kite::MVector{3, MyFloat}
    "vector of particle positions in x"
    X::MVector{P, MyFloat}
    "vector of particle positions in y"
    Y::MVector{P, MyFloat}
    "vector of particle positions in z"
    Z::MVector{P, MyFloat}
end 

StructTypes.StructType(::Type{SysState{P}}) = StructTypes.Mutable()

function sys_state_dict2struct(sys_state_dict)
   JSON3.read(sys_state_dict, SysState{P})
end

sys_state_dict2struct(sys_state_dict)

```

This fails with the error message:

```julia
ERROR: LoadError: MethodError: no method matching read(::Dict{Symbol, Any}, ::Type{SysState{11}})

Closest candidates are:
  read(::StructTypes.NumberType, ::Any, ::Any, ::Any, ::Any, ::Type{Integer}; kw...)
   @ JSON3 ~/.julia/packages/JSON3/jSAdy/src/structs.jl:67
  read(::StructTypes.NumberType, ::Any, ::Any, ::Any, ::Any, ::Type{Real}; kw...)
   @ JSON3 ~/.julia/packages/JSON3/jSAdy/src/structs.jl:65
  read(::StructTypes.NumberType, ::Any, ::Any, ::Any, ::Any, ::Type{Union{Bool, T}}; kw...) where T<:Real
   @ JSON3 ~/.julia/packages/JSON3/jSAdy/src/structs.jl:61
  ...

Stacktrace:
 [1] sys_state_dict2struct(sys_state_dict::Dict{Symbol, Any})
   @ Main ~/repos/KiteViewers.jl/mwes/mwe_09.jl:72
 [2] top-level scope
   @ ~/repos/KiteViewers.jl/mwes/mwe_09.jl:75
 [3] include(fname::String)
   @ Base.MainInclude ./client.jl:489
 [4] top-level scope
   @ REPL[1]:1
in expression starting at /home/ufechner/repos/KiteViewers.jl/mwes/mwe_09.jl:75

```

Any idea?

---

<div class="post-metadata">

**Author:** ![\_bernhard](https://avatars.discourse-cdn.com/v4/letter/_/bc79bd/32.png) [@\_bernhard](https://discourse.julialang.org/u/_bernhard)\
**Post date:** [July 27, 2024, 5:18pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550/2 "2024-07-27T17:18:21Z")

</div>

If you are not set on using `StructTypes` something along these lines could work.  
The code simply iterates over the names of all fields of your `struct` and sets them according to corresponding value in the `Dict` (assuming the key exists!!)

```julia
julia> module FooingDict

       mutable struct Foo
           a
           b
           c
           Foo()=new() # alternatively you could provide a constructor with default values
       end

       Foo(d::Dict) =
           let foo=Foo()
               for f in fieldnames(Foo)
                   setproperty!(foo, f, d[f])
               end
               foo
           end

       d = Dict(:a=>1, :b=>2, :c=>3)
       println(Foo(d))

       end;
Main.FooingDict.Foo(1, 2, 3)

```

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [July 27, 2024, 5:36pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550/3 "2024-07-27T17:36:45Z")

</div>

> [@\_bernhard](#):
>
> `Foo()=new() `

This was new to me. It works now:

```julia
using StaticArrays, StructTypes, JSON3

const MyFloat = Float64

sys_state_dict = Dict(:time => 0,
    :t_sim => 0,
    :sys_state => 0,
    :e_mech => 0,
    :orient => [0.530989, 0.466959, -0.466959, -0.530989],
    :elevation => 1.2426,
    :azimuth => 0,
    :l_tether => 150,
    :v_reelout => 0,
    :force => 559.847,
    :depower => 0.25,
    :steering => 0,
    :heading => 0,
    :course => 0,
    :v_app => 12.5799,
    :vel_kite => [0, 0, 0],
    :X => Union{Float64, Int64}[0, 8.90221, 17.5546, 25.9174, 33.9673, 41.687, 49.0618, 49.2317, 50.7465, 50.4513, 50.4513],
    :Y => Union{Float64, Int64}[0, 0, 0, 0, 0, 0, 0, 0, 0, 2.84247, -2.84247],
    :Z => Union{Float64, Int64}[0, 23.41, 46.9136, 70.5217, 94.2383, 118.064, 142.0, 147.029, 149.031, 146.739, 146.739]
)

P = 11
mutable struct SysState{P}
    "time since start of simulation in seconds"
    time::Float64
    "time needed for one simulation timestep"
    t_sim::Float64
    "state of system state control"
    sys_state::Int16
    "mechanical energy [Wh]"
    e_mech::Float64
    "orientation of the kite (quaternion, order w,x,y,z)"
    orient::MVector{4, Float32}
    "elevation angle in radians"
    elevation::MyFloat
    "azimuth angle in radians"
    azimuth::MyFloat
    "tether length [m]"
    l_tether::MyFloat
    "reel out velocity [m/s]"
    v_reelout::MyFloat
    "tether force [N]"
    force::MyFloat
    "depower settings [0..1]"
    depower::MyFloat
    "steering settings [-1..1]"
    steering::MyFloat
    "heading angle in radian"
    heading::MyFloat
    "course angle in radian"
    course::MyFloat
    "norm of apparent wind speed [m/s]"
    v_app::MyFloat
    "velocity vector of the kite"
    vel_kite::MVector{3, MyFloat}
    "vector of particle positions in x"
    X::MVector{P, MyFloat}
    "vector of particle positions in y"
    Y::MVector{P, MyFloat}
    "vector of particle positions in z"
    Z::MVector{P, MyFloat}
    SysState{P}() = new() 
end 

SysState{P}(d::Dict) =
let ss=SysState{P}()
    for f in fieldnames(SysState{P})
        setproperty!(ss, f, d[f])
    end
    ss
end

# StructTypes.StructType(::Type{SysState{P}}) = StructTypes.Mutable()

function sys_state_dict2struct(sys_state_dict)
   SysState{P}(sys_state_dict)
end

sys_state_dict2struct(sys_state_dict)

```

Thanks a lot!

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [July 27, 2024, 5:37pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550/4 "2024-07-27T17:37:22Z")

</div>

If you define your struct with [`Base.@kwdef`](https://docs.julialang.org/en/v1/base/base/#Base.@kwdef) you can do this:

```julia
sys_state_dict2struct(dict) = SysState{P}(; pairs(dict)...)

```

---

<div class="post-metadata">

**Author:** ![Satvik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/satvik/32/20486_2.png) [@Satvik](https://discourse.julialang.org/u/Satvik)\
**Post date:** [July 27, 2024, 5:46pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550/5 "2024-07-27T17:46:02Z")

</div>

Here’s a general version:

```julia
struct BasicStruct
       a::Int
       b::Int
end

function conform(::Type{T}, d::Dict)::T where T
           struct_inputs = [d[field_name] for field_name in fieldnames(T)]
           return T(struct_inputs...)
end

dict_data = Dict(:a => 2, :b => 3)

> conform(BasicStruct, dict_data)
BasicStruct(2, 3)

```

This should work as long as the dict has a key of the right type for each field of the struct.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [July 27, 2024, 6:05pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550/6 "2024-07-27T18:05:16Z")

</div>

It works. Different methods have a different performance:

```julia
sys_state_dict2struct(dict) = SysState{P}(; pairs(dict)...)

```

gives:

```julia
@btime sys_state_dict2struct($sys_state_dict)
  2.638 μs (50 allocations: 3.58 KiB)

```

and

```julia
SysState{P}(d::Dict) =
let ss=SysState{P}()
    for f in fieldnames(SysState{P})
        setproperty!(ss, f, d[f])
    end
    ss
end

sys_state_dict2struct(sys_state_dict) = SysState{P}(sys_state_dict)

```

results in

```julia
julia> @btime sys_state_dict2struct($sys_state_dict)
  3.562 μs (48 allocations: 1.39 KiB)

```

Not so sure yet what is more important for me, low allocations or high speed.

Nevertheless thanks a lot!

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [July 27, 2024, 9:15pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550/7 "2024-07-27T21:15:41Z")

</div>

Just curious, but what is the difference between this use case and your [previous question](https://discourse.julialang.org/t/how-to-convert-a-dict-to-a-struct/116916)?

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [July 27, 2024, 9:32pm UTC](https://discourse.julialang.org/t/how-to-create-a-struct-from-a-dict/117550/8 "2024-07-27T21:32:08Z")

</div>

My previous question assumed that the number of entries in the dict are smaller than the number of fields of the struct.

The key focus in the new question was how to make the conversion if all fields are present, but in a way that that changes to the struct propagate automatically (do not require any change in the function that does the conversion).
