How to convert a Dict to a Struct

How can I convert a dict to a struct?

I have the following code:

set_dict=Dict{String, Any}("log_level" => 1.0, "area" => 20.0, "solver" => "IDA")

mutable struct Settings
    log_level::Int64
    area::Float64
    solver::String
end

function set_struct(set_dict)
    set = Settings(0, 0, "")
    for (key, value) in set_dict
        print(key, ": "); println(value)
        # set field  of the struct with the name key to the corresponding value
    end
    set
end

set_struct(set_dict)

But how can I access the fields of a struct using a string variable?

The dictionary will usually have less entries than the struct has fields.

This works:

set_dict=Dict{String, Any}("log_level" => 1.0, "area" => 20.0, "solver" => "IDA")

mutable struct Settings
    log_level::Int64
    area::Float64
    solver::String
end

function set_struct(set_dict)
    set = Settings(0, 0, "")
    for (key, value) in set_dict
        # set field  of the struct with the name key to the corresponding value
        setproperty!(set, Symbol(key), value)
    end
    set
end

set_struct(set_dict)

You already solved it, but here is a way to make it a bit more compact if you like:

@kwdef struct Settings
        log_level::Int64
        area::Float64
        solver::String
end

set_dict = Dict{String, Any}("log_level" => 1.0, "area" => 20.0, "solver" => "IDA")
set_struct = Settings(; (Symbol.(keys(set_dict)) .=> values(set_dict))... )

This way, you can also avoid having a mutable Settings, which may or may not be handy.

Note that if the original Dict used symbols instead of strings, conversion to a struct would be trivial:

sym_dict = Dict{Symbol, Any}(:log_level => 1.0, :area => 20.0, :solver => "IDA")
set_struct = Settings(; sym_dict...)

Even without the @kwdef in plain Julia:

Settings(getindex.(Ref(set_dict),String.(fieldnames(Settings)))...)

gives:

Settings(1, 20.0, "IDA")
1 Like

Yes, but if

as in the original question, it get’s a bit longer, but the following is very general and also works for immutable structs:

struct Settings
    log_level::Int64
    area::Float64
    solver::String
end

function createme(prototype, dict)
    ST = typeof(prototype)
    fields = fieldnames(ST)
    ST(get.(Ref(dict), string.(fields), getfield.(Ref(prototype), fields))...)
end

proto = Settings(0, 0, "")
createme(proto, Dict("log_level" => 1.0, "area" => 20.0))
2 Likes