linking together array data for matching values

I’ve been digging around the Internet a bit, but still struggling on this one – any help?

I have been given two lists: 1) a list of people, and 2) a list of assets owned by people:

I am trying to identify and report on who owns what. I would like to produce a ‘complete’ dataset, where the assets are assigned people, like this:

I have been reading into how to combine arrays where they share a common value [In my case person name and object owner]. So far I have found information about merging flat arrays. Is it possible to merge nested arrays like this? If so, how?

Thanks in advance for your time and help!

There is probably some D3 magic (like rollup or group) to do it more efficiently, but with vanilla Javascript I’d do it like this:

{
  const map = new Map(person.map(obj => ([obj.name, {person: [obj], assets: []}])));
  for(const a of assets) map.get(a.owner).assets.push(a);
  return Array.from(map.values());
}

In detail:

{
  // person is the primary dataset, so we use it to prepare the final structure.
  const map = new Map(person.map(obj => ([
    // The item key
    obj.name,
    // The item value
    {
      person: [obj],
      // Initialize the assets array so that we can push items on it in the next step.
      assets: []
    }
  ])));
  for(const a of assets) {
    // Get the map entry (the object) via the asset.owner value,
    // then push this asset onto the assets array.
    map.get(a.owner).assets.push(a);
  }
  // Convert the map back into an array, discard the keys.
  return Array.from(map.values());
}
1 Like

The operation is a “group by” (assets grouped by owner) which might help the google-fu.

1 Like

Thanks @mootari and @tomlarkworthy !

@mootari - Thank you for the annotations. I had been floundering trying to use `.push` in a few of my attempt. This really helped to clarify!

@tomlarkworthy - Thank you for helping me learn the vocabulary, which does help the ‘google-fu’! :slight_smile: I note that the solution you linked, the reference to .groupBy() is from lodash. I probably shouldn’t be frightened, but I have been avoiding it thus far. Where I do reach for a helper library, I have been trying to work exclusively with D3 to help keep my learning… focused.

I read into D3.group, D3.rollup as my point of departure for this problem (Mike and others have helped me with these in the past, and I have some basic ability to use them), but was totally failing in my attempts. It’s definitely helpful to learn the ‘pure’ JS approach.

Thank you!

d3.group(assets, d => d.owner)

Should get you started?

2 Likes

Thanks Mike! I’ll try again soon. I was trying to follow the d3.index examples, which look like they should do what I want. I tried re-working the examples to achieve the output I was after, but unsuccessfully. I am away from a computer again, but from memory the pattern you provide above would re-format my assets so they are organized by owner. I would want then to bundle these outputs into the ‘persons’ array to create a single data object. This was where I was hitting the wall.

Thank you for your time and help!