2

I have two large arrays, one of items, the other of names who have the items. I need to push all the names who have the matching items into array2 items.

I can do this via a nest forEach loop:

array1 = [
  {item: "1", name: "Joe" },
  {item: "2", name: "Sam" },
  {item: "1", name: "Alice"},
  {item: "3", name: "Peter"},
  {item: "1", name: "Jack"},
]

array2 = [
  { item: "1", names: []},
  { item: "2", names: []},
  { item: "3", names: []},
]

array2.forEach(x => {
    array1.forEach(y => {
        if( x.item === y.item ){
        x.names.push(y.name)
        }
    })
})
console.log(array2)

But I have a sense this is bad practice and not to mention resource heavy on large arrays.

What is the moden way to do this?

Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
Jeffs
  • 35
  • 3
  • 1
    Bear in mind, that you may not always know available `item` values to group by them. So, things may go even worse as you'll need to traverse your source array to get unique `item` values to build up your `array2` from those. – Yevhen Horbunkov May 31 '21 at 12:42
  • 1
    To give you and idea of how nasty things might go like for 1k records with your solution compared to [mine](https://stackoverflow.com/a/67773764/11299053), for example, you may refer to this [benchmark](https://jsbench.me/s9kpclwrgi/1). – Yevhen Horbunkov May 31 '21 at 12:48
  • 1
    Ive learnt a tonne from your example and doc links, appreicate it – Jeffs Jun 02 '21 at 11:58

2 Answers2

3

I believe, you'd be much better off taking advantage of Map:

const src = [
        {item: "1", name: "Joe" },
        {item: "2", name: "Sam" },
        {item: "1", name: "Alice"},
        {item: "3", name: "Peter"},
        {item: "1", name: "Jack"},
      ],
      
      result = [...src
        .reduce((acc, {item,name}) => {
          const group = acc.get(item)
          group
            ? group.names.push(name)
            : acc.set(item, {item, names:[name]})
          return acc
        }, new Map)
        .values()
      ]
      
console.log(result)      
Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
  • This works perfectly, and clearly faster, although Ill be honest Im struggeling to understand some of the syntax used: "...", "?", ":", is there any good sources of documention to help understand whats going on here. – Jeffs May 31 '21 at 13:22
  • @Jeffs : no worries, mate. `...` is a [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) in a nutshell, it is used to turn iterator, returned by `Map.prototype.values()` into array; `condition ? then : else` is a [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) and is a shorthand form of `if.. then.. else..` – Yevhen Horbunkov May 31 '21 at 13:37
0
array2.forEach(a2 => { 
     let names = array1.filter(a1 => a1.item === a2.item)
                       ?.map(n => n.name); 
     a2.names = names ?? []; 
});
Vivek Bani
  • 3,703
  • 1
  • 9
  • 18