# Looping over structure elements by their names

**URL:** <https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946>\
**Category:** General Usage\
**Tags:** question\
**Created:** [August 18, 2022, 7:37pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946 "2022-08-18T19:37:32Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![tradler](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tradler/32/36214_2.png) [@tradler](https://discourse.julialang.org/u/tradler)\
**Post date:** [August 18, 2022, 7:37pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/1 "2022-08-18T19:37:32Z")

</div>

I am wondering how to loop over the elements of a structure by their names?

Big-picture, I have a structure which contains the parameters of an economic model, some of which are functions of other parameters. I would like to see how the model output changes when I vary a subset of parameters one at a time. Importantly, I want to make sure the parameter dependencies remain. For instance, in the MWE below, I’d like to have c and d also update when I update a and b. I believe this precludes me using something like SetField. I think it’d be easy to do this if I put the parameters in an array, but I’d like to be able to access them by name.

Concretely, I’m trying to see how particular simulated moments change and how the difference between the data moments and simulated moments changes.I haven’t figured out a way to do this which doesn’t involve copying the same block of code for each parameter, which is roughly what I’m doing in the testfunc() example below.

What I’d like is to have something like testfunc2(), which errors out because I cannot get the iterator to be recognized as a valid input to the myparams() structure. Per some previous threads in the discord I’ve tried experimenting with using metaprogramming in testfunc3(). This works in the REPL, but not otherwise, and I’m not sure if something like this is overkill for this type of problem.

```julia
@with_kw struct myparams
    a::Float64 = 0.03
    b::Float64 = 0.95
    c::Float64 = 1 / (1 + a)
    d::Float64 = a * b
end

function myobjfunc(p::myparams)
    @unpack a, b, c, d = p
    return (a + b) * (c + d)
end

function testfunc()

    p0 = myparams()
    steps = collect(0.5:0.1:1.5)
    vals = Array{Float64}(undef, 2, length(steps))

    for i = eachindex(steps)
        p = myparams(a=p0.a * steps[i])
        vals[1, i] = myobjfunc(p)

        p = myparams(b=p0.b * steps[i])
        vals[2, i] = myobjfunc(p)
    end

    return vals
end

function testfunc2()

    p0 = myparams()
    steps = collect(0.5:0.1:1.5)
    vals = Array{Float64}(undef, 2, length(steps))
    iter = 0
    for symb in (:a, :b)
        iter += 1
        for i = eachindex(steps)
            p = myparams(symb=p0.symb * steps[i])
            vals[iter, i] = myobjfunc(p)
        end
    end

    return vals
end

function testfunc3()

    p0 = myparams()
    steps = collect(0.5:0.1:1.5)
    vals = Array{Float64}(undef, 2, length(steps))
    iter = 0
    for symb in (:a, :b)
        iter += 1
        for i = eachindex(steps)
            ex = :(myparams($symb=p0.$symb * steps[i]))
            p = eval(ex)
            vals[iter, i] = myobjfunc(p)
        end
    end

    return vals
end

testfunc()
2×11 Matrix{Float64}:
 0.96449 0.967437 0.9704 0.973379 0.976375 0.979386 0.982414 0.985459 0.988519 0.991596 0.994689
 0.497488 0.592784 0.688623 0.785002 0.881924 0.979386 1.07739 1.17594 1.27502 1.37465 1.47482

testfunc2()
ERROR: type myparams has no field symb

testfunc3()
ERROR: UndefVarError: p0 not defined

```

Any advice would be greatly appreciated! This seems it should be simple to implement, so I’ve been a bit frustrated by how it has stumped me…

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [August 18, 2022, 7:50pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/2 "2022-08-18T19:50:48Z")

</div>

I’m not sure if I understand what you want, but have you thought about overloading `getindex` for your type?

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [August 18, 2022, 8:00pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/3 "2022-08-18T20:00:32Z")

</div>

You can use `Setfield.setproperties`

```julia
julia> using Setfield, Parameters

julia> @with_kw struct myparams
           a::Float64 = 0.03
           b::Float64 = 0.95
           c::Float64 = 1 / (1 + a)
           d::Float64 = a * b
       end
myparams

julia> m = myparams()
myparams
  a: Float64 0.03
  b: Float64 0.95
  c: Float64 0.970873786407767
  d: Float64 0.028499999999999998

julia> symb = :c
:c

julia> setproperties(m, NamedTuple{(symb,)}(1))
myparams
  a: Float64 0.03
  b: Float64 0.95
  c: Float64 1.0
  d: Float64 0.028499999999999998

```

There might be a more elegant solution, though.

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [August 18, 2022, 8:12pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/4 "2022-08-18T20:12:55Z")

</div>

- Maybe a `NamedTuple` is a good type for you to use.

```julia
params(;a = 0.03, b = 0.95, c = 1/(1+a), d = a * b) = (;a, b, c, d) 

```

You can use it like this

```julia
p = params(a=1.0)
p = params(a=1.0; c = 2.0) # if you want to overwrite c with another value
p = params(a=1.0, b=2.0) 

```

To access the values, you can use

```julia
@unpack a, b, c, d = p
# or 
x = p.c

```

And code like this should be fairly efficient, since Julia can optimize it well

```julia
function myobjfunc(p)
    @unpack a, b, c, d = p
    return (a + b) * (c + d)
end

vals_a = myobjfunc.( ( params(a=a) for a in 0.5:0.1:1.5 ) )
vals_b = myobjfunc.( ( params(b=b) for b in 0.5:0.1:1.5 ) )
vals_ab = myobjfunc.( ( params(; sym => x ) for sym in (:a,:b), x in 0.5:0.1:1.5 ) )

```

* * *

EDIT: Used nicer syntax to create named tuple, see [Essentials · The Julia Language](https://docs.julialang.org/en/v1/base/base/#Core.NamedTuple)

---

<div class="post-metadata">

**Author:** ![tradler](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tradler/32/36214_2.png) [@tradler](https://discourse.julialang.org/u/tradler)\
**Post date:** [August 18, 2022, 8:15pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/5 "2022-08-18T20:15:07Z")

</div>

I think the issue with this is that it won’t update the parameters that are functions of the parameter being updated. For instance, if I change :a I want :c to change as well.

```julia

julia> @with_kw struct myparams
                  a::Float64 = 0.03
                  b::Float64 = 0.95
                  c::Float64 = 1 / (1 + a)
                  d::Float64 = a * b
              end
myparams

julia> myparams
myparams

julia> m = myparams()
myparams
  a: Float64 0.03
  b: Float64 0.95
  c: Float64 0.970873786407767
  d: Float64 0.028499999999999998

julia> symb = :a
:a

julia> setproperties(m, NamedTuple{(symb,)}(1))
myparams
  a: Float64 1.0
  b: Float64 0.95
  c: Float64 0.970873786407767
  d: Float64 0.028499999999999998

```

c is the same as before here, but I’d want it to be 1/(1+a) = 1/2.

---

<div class="post-metadata">

**Author:** ![tradler](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tradler/32/36214_2.png) [@tradler](https://discourse.julialang.org/u/tradler)\
**Post date:** [August 18, 2022, 8:52pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/6 "2022-08-18T20:52:28Z")

</div>

This definitely seems promising! To be clear, I think what I was looking for was a way to iterate over symbols in the struct I created, as you do here:

```julia
vals_ab = myobjfunc.( ( params(; NamedTuple{(sym,)}((x,))... ) for sym in (:a,:b), x in 0.5:0.1:1.5 ) )

```

In non-MWE-world, I hadn’t been sure whether using a struct to hold the parameter values was necessary for this problem, but also hadn’t seen a reason to switch to using NamedTuples. This certainly seems like enough of a reason to switch.

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [August 18, 2022, 9:05pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/7 "2022-08-18T21:05:46Z")

</div>

Actually, the same code probably works with `params` replaced by your type `myparams`😃

```julia
vals_ab = myobjfunc.( ( myparams(; sym =>x ) for sym in (:a,:b), x in 0.5:0.1:1.5 ) )

```

---

<div class="post-metadata">

**Author:** ![tradler](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tradler/32/36214_2.png) [@tradler](https://discourse.julialang.org/u/tradler)\
**Post date:** [August 18, 2022, 10:03pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/8 "2022-08-18T22:03:29Z")

</div>

Actually, I’m realizing that this doesn’t do quite what I want. The purpose of the iterator from .5 to 1.5 is to scale the original parameter guess from 50% of it’s original value to 150% of the original value, so I’d need something like

```julia
vals_ab = myobjfunc.( ( myparams(; sym =>x*p0[sym] ) for sym in (:a,:b), x in 0.5:0.1:1.5 ) )

```

but then I’m back to the same original problem. Sorry if I’m being dense…

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [August 18, 2022, 10:32pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/9 "2022-08-18T22:32:51Z")

</div>

Mh, I think it is not completely clear what exactly the goal is. And in the end the solution should be not too complicated as well.

This for example would create a 10 by 10 matrix with all the values `a` and `b` scaled between 50% (helf) and 200% (double):

```julia
p_def = myparams()
a_factors = p_def.a * 2 .^ LinRange(-1,1,10)
b_factors = p_def.b * 2 .^ LinRange(-1,1,10)

vals_ab = myobjfunc.( myparams(; a, b ) for a in a_factors, b in b_factors )

```

Of course, if you really want to scale in one line, you could also define

```julia
function scale_params(p_def = myparams(); factors...)
    scaled_params = [sym => p_def[sym] * s for (sym, s) in factors]
    return myparams(; scaled_params... )
end

```

and then use

```julia
vals_ab = myobjfunc.( scale_params(; a, b ) for a in 2 .^ LinRange(-1,1,10), b in 2 .^ LinRange(-1,1,10) )

```

---

<div class="post-metadata">

**Author:** ![tradler](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tradler/32/36214_2.png) [@tradler](https://discourse.julialang.org/u/tradler)\
**Post date:** [August 18, 2022, 10:33pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/10 "2022-08-18T22:33:31Z")

</div>

Would the idea here to be to associate each parameter with an integer value? Something like

```julia
Base.getindex(p::myparams, i::Int) = p.a*(i == 1) + p.b*(i == 2) + p.c*(i == 3) + p.d*(i==4)

```

then something like

```julia
function testfunc4()

    p0 = myparams()
    steps = collect(0.5:0.1:1.5)
    vals = Array{Float64}(undef, 2, length(steps))

    iter = 0
    for sym in (:a, :b)
        iter += 1
        for i in eachindex(steps)
            p = myparams(; sym => p0[iter] * steps[i])
            vals[iter, i] = myobjfunc(p)
        end
    end

    return vals
end

```

using some of the syntax from @SteffenPL would work? This gives the right answer but seems pretty inelegant, which I’d take at this point. I suppose I could create a tuple that associates the symbols with their integer value, which eliminates the need for updating the “iter”.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [August 18, 2022, 10:45pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/11 "2022-08-18T22:45:18Z")

</div>

Not sure if I’m reading this problem really wrong, but `fieldnames(myparams)` gets you `(:a, :b, :c, :d)` if you need to iterate over the field names. `Core.getfield` can accept either integers or symbols to get to the fields:

```julia
julia> getfield.(Ref(myparams()), Tuple(1:4))
(0.03, 0.95, 0.970873786407767, 0.028499999999999998)

julia> fieldnames(myparams)
(:a, :b, :c, :d)

julia> getfield.(Ref(myparams()), fieldnames(myparams))
(0.03, 0.95, 0.970873786407767, 0.028499999999999998)

```

The `Ref` is to wrap the instance in a 1-element iterable to act as a scalar, `myparams()` isn’t iterable so broadcasting would’ve just failed.

---

<div class="post-metadata">

**Author:** ![tradler](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tradler/32/36214_2.png) [@tradler](https://discourse.julialang.org/u/tradler)\
**Post date:** [August 18, 2022, 11:00pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/12 "2022-08-18T23:00:13Z")

</div>

@SteffenPL  
I definitely agree that the solution should not be too complicated 🙂  
The big-picture goal is to see how sensitive the model outputs are to their inputs, and how smooth that relationship is. In non-MWE world I’ve got ~20 parameters which end up affecting behavior in a simulated economy. I want to see, for instance, how the employment rate in the simulated economy changes as I vary the parameters one at a time over some range. I’d want to do this for a pretty large number of model outputs, ~60. The main goal of posting was to figure out how to get the correct syntax so this could scale up without copy-pasting a bunch 🙂

@Benny I think this, in combination with one of @SteffenPL’s earlier answers, gets me what I want, although the code could probably be written more compactly.

```julia
function testfunc()

    p0 = myparams()
    steps = collect(0.5:0.1:1.5)
    vals = Array{Float64}(undef, 2, length(steps))

    iter = 0
    for sym in (:a, :b)
        iter += 1
        for i in eachindex(steps)
            p = myparams(; sym => getfield.(Ref(p0), sym) * steps[i])
            vals[iter, i] = myobjfunc(p)
        end
    end

    return vals
end

```

Thanks everyone, this was very helpful!

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [August 18, 2022, 11:17pm UTC](https://discourse.julialang.org/t/looping-over-structure-elements-by-their-names/85946/13 "2022-08-18T23:17:47Z")

</div>

👍  
By the way, in your example `getfield(p0,sym)` works as well. In the post from Benny the `Ref` was just needed to get multiple fields at the same time 😉
