Does this style of “property broadcasting” already exist?

I also find this way of manipulating data convenient. It can easily represent plain tables, so that one basically doesn’t need specialized packages for them. And when flat tables aren’t enough, it directly generalizes to higher-dim arrays, or arrays containing something else, not just named tuples.

A nice, efficient (due to StructArrays) implementation:

julia> using StructArrays, AccessorsExtra

# create single-row table
julia> tbl = StructArray([(x = 0,)])
1-element StructArray(::Vector{Int64}) with eltype NamedTuple{(:x,), Tuple{Int64}}:
 (x = 0,)

# make it three-row by replacing the only column
julia> tbl = @set tbl.x = 1:3
3-element StructArray(::UnitRange{Int64}) with eltype NamedTuple{(:x,), Tuple{Int64}}:
 (x = 1,)
 (x = 2,)
 (x = 3,)

# add another column from explicit values
julia> tbl = @insert tbl.y = [10, 20, 30]
3-element StructArray(::UnitRange{Int64}, ::Vector{Int64}) with eltype NamedTuple{(:x, :y), Tuple{Int64, Int64}}:
 (x = 1, y = 10)
 (x = 2, y = 20)
 (x = 3, y = 30)

# or by combining existing columns
julia> tbl = @insert tbl.z = tbl.x .* tbl.y
3-element StructArray(::UnitRange{Int64}, ::Vector{Int64}, ::Vector{Int64}) with eltype NamedTuple{(:x, :y, :z), Tuple{Int64, Int64, Int64}}:
 (x = 1, y = 10, z = 10)
 (x = 2, y = 20, z = 40)
 (x = 3, y = 30, z = 90)

Note that each step creates a new table: treating data as immutable is the Accessors.jl philosophy. But it’s efficient and doesn’t copy unchanged columns due to how StructArrays work.

This works with arrays of arbitrary dimensions, of course, but all components (x, y, z here) should have the same size: they are semantically treated as components of a single array.

1 Like