I have an array instantiated structures (of the same type). I would like to change the value of a certain field of these structures. For performance reasons I would like to avoid using a for loop. Here's a toy code to illustrate what I do:
mutable struct foo
x
end
a,b = foo(5), foo(7)
arr = [a,b]
.-(getfield.(arr,:x),1)
I expected this to get the x fields into an array (of pointers to the actual x fields of the actual foo's) then apply -1 to all these.
When I call a,b
they are unchanged. I know after debugging that this is because broadcast()
of getfield materializes (Broadcast.materialize
) the fields into a new array, i.e. it is copied.
Is there a proper and performant way to do this without loops ?
Thank you
The loop should be fast, as Matt B. has indicated. However, if you want to avoid loops (mostly for convenience reasons) you can write either:
foreach(v -> v.x -= 1, arr)
(which actually is a kind of loop, but I would not expect it to be faster than a loop)
or use StructArrays.jl which is excellent from my experience. What you want can be achieved e.g. like this (using your arr
):
using StructArrays
arr2 = StructArray(arr)
arr2.x .-= 1
and StructArrays.jl takes care to subtract 1
from field x
in all elements of arr2
.
EDIT And you can expect StructArray
to be sometimes faster if you perform column-wise operations in comparison to a for
loop over collection of structs (in your example the field has type Any
so this should be not relevant, but if it had e.g. type Int
and the struct had many fields you could notice the difference).