For loop on a structure's field names

Hi everyone, hope you are all healthy.

I’m a mechanical engineering student and I come from MATLAB, so I am sorry for my heresies.

I have a structure with 13 fields, each of which is a structure with 10 fields, for example:

mutable struct b
   b1::some type
   b2::some type
   b3::some type
   ...
   b10::some type
end
struct a
   a1::b
   a2::b
   a3::b
   ...
   a13:b
end

I have to loop on the 13 fields to assign a new value at the field b4 for example, how can I do it in Julia?
In MATLAB I used to create an array of strings containing the 13 field names of the struct a:

afieldnames = ["a1" "a2" ... "a13"]

and then with the following loop I can access the field of b4 for each field of a as:

for i = 1:13
   a.(afieldnames(i)).b4 = somevalue
end

I know I can use the fieldnames and then getfield functions as shown in this https://discourse.julialang.org/t/how-to-write-a-fast-loop-through-structure-fields/22535, but I’m not able to do that for structure inside of structures.
Thank you all in advance, and I hope I haven’t broken too many rules!

Welcome!

Before we get into how to do this, are you sure this is actually what you want? You’re jumping through a lot of hoops to do something that would be trivial to do with a regular old vector. For example, what if you were to just replace a with a Vector{b} and b with a Vector{some type}? Then you could loop over the elements of a without needing to do anything special. And, as a bonus, the resulting code will be shorter and much more efficient. I’m happy to provide more detail if that’s a direction you want to go in.

4 Likes

First of all thank you for the attention! It is true that julia comunity is very friendly!!
Shurely I could do it with some vectors and matrices, but it would be messier I guess.

I am trying to implement the dempster’s model to perform some calculations on a human body inertial properties. In order to do that the body is divided in 14 segments, each of which has its own length, mass, centre of mass,…

The structure a mentioned above would be a collector of the segments, so:

struct a
   head&neck::b
   right fore arm::b
   right thigh::b
   .....
end

while the structure b a collector of the properties, so

mutable struct b
   segment length::float64
   segment mass::float64
   ....
end

The structure is mutable since some values of the field are calculated in a function, it works, but I dont know if it is the best way to do it.

Since a lot of calculations are the same for each segment, for example the length of the segment is related to the height of the subject, I would like to compute them in the for loop in the fields of the structure a.
If there is a cleaner way to implement I would really appreciate your advices. My goal for this implemantation of the dempster’s model is to make it easy to read, not pure performance, since all the calculations can be done by hand in less than an hour.

Thank you very much!

1 Like

Just to chime in here with my opinion: @rdeits has it right. This is probably much better suited for a vector of vectors or a matrix. You’ll get the advantages of optimized looping/indexing, for one, and I’ll bet you’ll get improved cache locality as well.

Might I suggest a 13 (row) x 10 (column) matrix of some type, where each row corresponds to a single a struct and the columns are elements in your b structs? I suggest this because Julia’s matrices are column-optimized and it sounds like you’re looping through a given element in b across all as.

If you want labels for the arrays for easier indexing, check out NamedArrays.jl (disclaimer: I haven’t used it) or even DataFrames.jl.

1 Like

Hi thank you for your answer.

My issue with using matrices and vectors is that retrieving information for a single segment would be less clean since I would have to call the centre of mass, the moment of inertia, the mass, the length,…, while with the structure it would be done in a single line of code (a.arm would contain all the informations about the arm of the subject). By the way if it is really that bad to do what I meant to do I will switch to matrix.

You could always write 1 function that given the matrix calls everything you need and bundles it up.

I came up with another good reason to have something similar to this.

Suppose that I have to perform some experimental tests on a set of specimens with different properties. In MATLAB I used to create a structure organized as follows:

struct infos 
   temperature::Float64
   time::Float64
   relativeHumidity::Float64
   loggedData1::Array{Float64,2}
   loggedData2::Array{Float64,2}
   ....
end

struct data
   specimen1::infos
   specimen2::infos
   specimen3::infos
   ...
   specimenN::infos
end

Then if I had to perform the same calculation for all the specimens I would use the for loop mentioned above. Should I do it in an other way?

Thnak you all

Maybe this was suggested but just

data = [speciment1, speciment2, ...]
1 Like

If each “body” is some overall info about the body (height, weight, subject identity, etc…) and a list of segments, you could probably organize it as

struct Segment
    length::Float64
    mass::Float64
end
struct Body
    height::Float64
    segments::Vector{Segment}
end

and now body.segments[i] gives you the i-th segment. Note that you probably don’t need to make Segment mutable: you can just set the i-th element of the vector to a new Segment struct, without mutating the old one (it tends to be more efficient).

If body.segments[i] is a bit “unreadable” and you’d prefer to refer to the i-th segment by name (say arm or thigh) you can use (as suggested above) a data structure that is like an array, but also keeps a label, check out for example GitHub - SciML/LabelledArrays.jl: Arrays which also have a label for each element for easy scientific machine learning (SciML) (there are many alternatives, I personally haven’t really used any so can’t offer much advice here).

2 Likes

Using @kristoffer.carlsson’s suggestion is, I think, the idiomatic way to do this. When you have a collection of like-typed objects, create some collection of them, whether it’s a vector, a set, or something else. In my experience, Julia can optimize better for collections than it can some arbitrary structure, and you ultimately end up with cleaner / more idiomatic code.

2 Likes

thanks a lot for your time, I will try this solution that to me looks the best!

I managed to implement it in this way. Thanks a lot!!

1 Like