Unstack via group_vg;map

using DataManipulation, StructArrays, PrettyTables
julia> let d = StructArray(a=[1,1,2,2], b=[:x, :y, :x, :y], c=[10, 20, 30, 40])
           pretty_table(d)
           @p begin
               d
               group_vg((;_.a,))
               map((;key(_)..., (_.b .=> _.c)...))
               pretty_table
           end
       end
┌───────┬────────┬───────┐
│     a │      b │     c │
│ Int64 │ Symbol │ Int64 │
├───────┼────────┼───────┤
│     1 │      x │    10 │
│     1 │      y │    20 │
│     2 │      x │    30 │
│     2 │      y │    40 │
└───────┴────────┴───────┘
┌───────┬───────┬───────┐
│     a │     x │     y │
│ Int64 │ Int64 │ Int64 │
├───────┼───────┼───────┤
│     1 │    10 │    20 │
│     2 │    30 │    40 │
└───────┴───────┴───────┘

Is there a nicer approach to table unstack?

Elements a little less elegant than I’d like:

  • the key ... splat
  • the .=> broadcast
  • the pairs ... splat

cc @aplavin

I think this pipeline you wrote is quite reasonable, especially splatting key(_)... is generally common thing to do. What is a bit tricky, is if you have different number of rows in each group and want to keep type stability… I thought about better ways for this operation a few times, but never really for long – personally for me, it comes up very rarely.

Typically, I find it natural to aggregate/process each group immediately, without materializing the full longer table. Or store values from each group in a data structure, either an array or a dict in this case:

@p let
	StructArray(a=[1,1,2,2], b=[:x, :y, :x, :y], c=[10, 20, 30, 40])
	@aside pretty_table()
	group_vg((;_.a,))
	map((;key(_)..., vals=Dict(_.b .=> _.c)))
end