Extract a field from an array of structures

I was wondering if there is a more elegent way to extract a field from an array of structures. An example follows:


julia> struct Foo
           i::Int
           v::Vector{Int}
       end

julia> foo = Vector{Foo}(undef, 2)
2-element Vector{Foo}:
 #undef
 #undef

julia> foo[1] = Foo(1, [1, 2])
Foo(1, [1, 2])

julia> foo[2] = Foo(3, [6, 8])
Foo(3, [6, 8])

julia> foo
2-element Vector{Foo}:
 Foo(1, [1, 2])
 Foo(3, [6, 8])

julia> # obtain the first field of the vector of structures

julia> [foo[a].i  for a in 1:length(foo)]
2-element Vector{Int64}:
 1
 3

julia>

There is GitHub - JuliaArrays/StructArrays.jl: Efficient implementation of struct arrays in Julia

1 Like

You can use broadcasting with either the getproperty or getfield functions:

julia> getproperty.(foo, :i)
2-element Vector{Int64}:
 1
 3

julia> getfield.(foo, :i)
2-element Vector{Int64}:
 1
 3
2 Likes

If you want to do it with a comprehension, this is shorter and better:

[x.i for x in foo]
6 Likes

Shorter it is, better is debatable. The broadcast solution is probably better situations in you want dot fusion to happen, and the StructArrays is a more general solution.

1 Like

It absolutely is better than the indexing version. For one thing it doesn’t assume anything about the axes, and it does natural iteration.

4 Likes

English isn’t my first language but I thought I made it clear that I compared my proposal to the quoted comprehension approach. I had no intention to claim anything about its relative merits to other solutions.

2 Likes

I apologize, I must have read it fast. In retrospective, it is obvious that you are improving just on the previous comprehension solution. What seems to have caused my confusion is that I did not scroll down all of Jake’s code. So when I saw you were referring one previous alternative I thought you could only be referring to the broadcast or the package.

2 Likes