Arquero Groups to Nested Arrays?

Hi All,

As the title suggestions I want to group a table by several keys, then output a nested array of the data.
So far the strategy I’ve come up with is:

{
  const df = aq.from(data).groupby(['key1', 'key2']);
  const {keys} = df.groups();
  const grouped = [];
  for (const [k,v] of Object.entries(keys)) {
    if (!grouped[v]) {
      grouped[v] = [];
    }
    grouped[v].push(data[k]);
  }
  return grouped;
}

I was wondering if there’s a cleaner way to do this?

Thank you!

You could try to use something like Python’s defaultdict to slightly simplify the code.

A google search turns up GitHub - jsoendermann/defaultdict-proxy: A Proxy based JavaScript port of python's defaultdict.

Probably not worth importing a library if you only have to do this a couple times though.

1 Like

Thank you! Yeah I only need it a few times, so it should be fine. Was mostly curious if there was an “idiomatic” solution.

I wouldn’t mark this as ‘solved’ just yet. Maybe someone else has a better idea.

1 Like

We can make things at least a tiny bit shorter, though maybe less legible depending on your intended audience:

{
  const df = aq.from(data).groupby(['key1', 'key2']);
  const grouped = [];
  [].forEach.call(df.groups().keys, (x, i) =>
    (grouped[x] ||= []).push(data[i]));
  return grouped;
}
1 Like

Go directly against ‘data’ with d3.groups. If you need to do some other ‘data-wrangling’ with Arquero prior to needing the final grouping, reference table.objects() as the first parameter to the d3.groups method:

{
const d3 = await require(“d3-array”);

// Sample data:
const data = [{key1:10, key2: 20, val: 1}, {key1:10, key2: 20, val: 2}, {key1:10, key2: 30, val: 3}];

return d3.groups(data, d => d.key1, d => d.key2)[0][1].map(([_,d]) => d)
}

1 Like

I thought some more about this issue and made a draft PR to add a grouped output feature. In the discussion, Jeff explains more idiomatic ways to use a combination of aq.create(), aq.rollup(), and op.array_agg() to achieve a similar effect.

1 Like

As of Arquero v4.1.0, aq.objects() accepts the { grouped } option, which allows grouped output. Therefore, the idiomatic code for my question above would be:

aq.from(data)
  .groupby(["key1", "key2"])
  .objects({grouped: "entries"});
1 Like