How to create and fill a vector of Struct as in a Matrix?

I have a struct of Rs and a vector R of it. Currently, I am using such the below code to construct R and then change the values of its fields.

Base.@kwdef mutable struct Rs
    I::Vector{Float64} = [2,2,2]
    Dot::Array{Float64, 2} = [0 0 0; 0 0 0; 0 0 0]
end
R = Rs[];
push!(R, Rs()); # the values of fields may change in the code
push!(R, Rs()); # the values of fields may change in the code
julia> R
2-element Vector{Rs}:
 Rs([2.0, 2.0, 2.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])
 Rs([2.0, 2.0, 2.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])
#Modify the values of the fields, such as
#R[index1].I[index2] = value;

Is there any way to construct R and fill the values of its fields as in Matrix, such as below?

Base.@kwdef mutable struct Rs
    I::Vector{Float64} = [2,2,2]
    Dot::Array{Float64, 2} = [0 0 0; 0 0 0; 0 0 0]
end
R = Vector{Rs}[([5.0, 5.0, 4.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]);
   ([3.0, 2.0, 7.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])];

maybe. (Note the dot)

1 Like

@leandromartinez98 Thank you!
I have tried but gave me an error:

julia> U = Rs.[([5.0, 5.0, 4.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]),
          ([3.0, 2.0, 7.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])]
ERROR: syntax: invalid syntax "Rs.[([5, 5, 4], [0 0 0; 0 0 0; 0 0 0]), ([3, 2, 7], [0 0 0; 0 0 0; 0 0 0])]" around REPL[8]:1
Stacktrace:
 [1] top-level scope
   @ REPL[8]:

I think you want

R = map(args -> Rs(args...), [([5.0, 5.0, 4.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]);
   ([3.0, 2.0, 7.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])])
3 Likes

Uhm… not sure why that does not work.

Edit: maybe just adding a parenthesis:

struct A x end
@show A.([1, 2])

Works

1 Like

@stevengj Thank you! it works.
@lmiq @stevengj Do you think the structure of R is complicated in Julia and affect the performance?

If the arrays are that small, use Static Arrays

2 Likes

If you always have 3-component vectors and 3x3 matrices (or in general small vectors/matrices whose size is always the same, e.g. equal to the number of spatial dimensions in a geometry), then you should consider using StaticArrays.

2 Likes

@lmiq is it as below?

julia> X =Rs.([([5.0, 5.0, 4.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]),
          ([3.0, 2.0, 7.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])])
ERROR: MethodError: no method matching Rs(::Tuple{Vector{Float64}, Matrix{Float64}})
Closest candidates are:
  Rs(::Any, ::Any) at REPL[3]:2
  Rs(; I, Dot) at util.jl:450
1 Like

I see, I thought that would work… Cannot really test things now. If you use that often you may want a custom constructor then.

1 Like

I only need it once at the beginning of my code (input of my network data)

This is in a sense a mix of Leandro and Steve’s answers.

   Base.splat(Rs).([([5.0, 5.0, 4.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]);
   ([3.0, 2.0, 7.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])])
2 Likes

The problem here is that the constructor does not take a single object that is a tuple of two values but instead it takes two separate objects. Unfortunately this means you cannot just use broadcast and apply the constructor element-wise to a single vector of two-element tuples but instead you need to apply the constructor element-wise to two vectors instead. I adapted the try above to the correct form below:

julia> R = Rs.(
    [[5.0, 5.0, 4.0], [3.0, 2.0, 7.0]], # vector of first parameters
    [[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]] # vector of second parameters
)
2-element Array{Rs,1}:
 Rs([5.0, 5.0, 4.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])
 Rs([3.0, 2.0, 7.0], [0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])

3 Likes