# Converting a vector of structs to a struct of vectors

Hello,

I have the following struct:

``````using Rotations, StaticArrays

const MyFloat = Float32
const SEGMENTS = 7                    # number of tether segments

struct SysState
time::Float64                     # time since launch in seconds
orient::Quat                      # orientation of the kite
X::MVector{SEGMENTS+1, MyFloat}   # vector of particle positions in x
Y::MVector{SEGMENTS+1, MyFloat}   # vector of particle positions in y
Z::MVector{SEGMENTS+1, MyFloat}   # vector of particle positions in z
end
``````

Then I create an array of these structs:

``````# create a demo state with a given height and time
function demo_state(height=6.0, time=0.0)
a = 10
X = range(0, stop=10, length=SEGMENTS+1)
Y = zeros(length(X))
Z = (a .* cosh.(X./a) .- a) * height/ 5.430806
orient = UnitQuaternion(1.0,0,0,0)
return SysState(time, orient, X, Y, Z)
end

# create a demo flight log with given name [String] and duration [s]
const SAMPLE_FREQ=20
function demo_log(name="Test flight", duration=10)
delta_t = 1.0 / SAMPLE_FREQ
t_max   = 10.0
max_height = 6.0
steps   = Int(t_max * SAMPLE_FREQ) + 1
log = Vector{SysState}(undef, steps)
for i in range(0, length=steps)
log[i+1] = demo_state(max_height * i/steps, i*delta_t)
end
return log
end
``````

Finally I want to create a struct of vectors (sov) out of this vector of structs (vos) to be able to access the elements easily, like that:

``````vos = demo_log()
sov = vos2sov(vos)   # how can I implement this function?
println(sov.time)    # should print a vector of Float64
println(sov.orient)  # should print a vector of quaternions
``````

How can I implement the function vos2sov?

I looked at the package StructArrays.jl, but it seams as if it cannot handle structs that are composed of different types.

I was wrong, StructArrays CAN handle structs that are composed of different types. Example:

``````using StructArrays

struct Compound
time::Float64
name::String
end

sa = StructArray{Compound}(([1.0, 2.0], ["Hund", "Hase"]))

println(sa.time)
println(sa.name)
``````

I still have to figure out how to implement the function vos2sov in a generic way. I don’t want to change this function when the struct changes.

1 Like

Ok, this function partially works:

``````function vos2sov(log::Vector)
steps=length(log)
time_vec = Vector{Float64}(undef, steps)
orient_vec = Vector{Quat}(undef, steps)
X_vec = Vector{MVector{SEGMENTS+1, MyFloat}}(undef, steps)
Y_vec = Vector{MVector{SEGMENTS+1, MyFloat}}(undef, steps)
Z_vec = Vector{MVector{SEGMENTS+1, MyFloat}}(undef, steps)
for i in range(1, length=steps)
state=log[i]
time_vec[i] = state.time
orient_vec[i] = state.orient
X_vec[i] = state.X
Y_vec[i] = state.Y
Z_vec[i] = state.Z
end
return StructArray{SysState}((time_vec, orient_vec, X_vec, Y_vec, Z_vec))
end
``````

How can I rewrite it such that it works with any struct in a generic way?

Maybe you could try working with list comprehension.

``````julia> struct Foo
a
end

julia> foo = Foo(1.0)
Foo(1.0)

julia> fa = [foo, foo]
2-element Vector{Foo}:
Foo(1.0)
Foo(1.0)

julia> a = [x.a for x in fa]
2-element Vector{Float64}:
1.0
1.0

julia> struct Sol
a
end

julia> sol = Sol(a)
Sol([1.0, 1.0])
``````