What would be the most efficient way to group items by the name key in a nested array/object?
The main array looks something like this here:
let arr = [
{
id: 123,
compensatedItems: [
{
name: 'Random item 1',
id: '123512',
reason: 'missing_items',
},
{
name: 'Random item 1',
id: '123512',
reason: 'missing_items',
},
{
name: 'Random item 1',
id: '123512',
reason: 'missing_items',
},
{
name: 'Another random item',
id: '24122',
reason: 'missing_items',
},
{
name: 'Another random item',
id: '24122',
reason: 'missing_items',
},
],
},
{
id: 341,
compensatedItems: [
{
name: 'Random item 1',
id: '123512',
reason: 'missing_items',
},
{
name: 'Random item 1',
id: '123512',
reason: 'missing_items',
},
{
name: 'Another random item',
id: '24122',
reason: 'missing_items',
},
],
},
];
Where you have a main array that has multiple objects, and each object has a compensatedItems array with additional objects in it.
I'd like to get the compensatedItems grouped by the name so that the end result would look something like
let res = [
{
name: 'Random item 1',
id: '123512',
reason: 'missing_items',
count: 5,
},
{
name: 'Another random item',
id: '24122',
reason: 'missing_items',
count: 3,
},
];
Its one of those days when nothing makes sense and having a hard time coming up with an efficient solution without looping 1000 times. 🤦🏼♂️
Thanks!
You could get an array of compensatedItems and use your favourite grouping/counting algorithm/function.
const
data = [{ id: 123, compensatedItems: [{ name: 'Random item 1', id: '123512', reason: 'missing_items' }, { name: 'Random item 1', id: '123512', reason: 'missing_items' }, { name: 'Random item 1', id: '123512', reason: 'missing_items' }, { name: 'Another random item', id: '24122', reason: 'missing_items' }, { name: 'Another random item', id: '24122', reason: 'missing_items' }] }, { id: 341, compensatedItems: [{ name: 'Random item 1', id: '123512', reason: 'missing_items' }, { name: 'Random item 1', id: '123512', reason: 'missing_items' }, { name: 'Another random item', id: '24122', reason: 'missing_items' }] }],
countBy = (array, key) => Object.values(array.reduce((r, o) => {
r[o[key]] ??= { ...o, count: 0 };
r[o[key]].count++;
return r;
}, {})),
result = countBy(
data.flatMap(({ compensatedItems }) => compensatedItems),
'name'
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can reduce a flatted array with the compensated items as follows:
const arr = [ { id: 123, compensatedItems: [ { name: 'Random item 1', id: '123512', reason: 'missing_items', }, { name: 'Random item 1', id: '123512', reason: 'missing_items', }, { name: 'Random item 1', id: '123512', reason: 'missing_items', }, { name: 'Another random item', id: '24122', reason: 'missing_items', }, { name: 'Another random item', id: '24122', reason: 'missing_items', }, ], }, { id: 341, compensatedItems: [ { name: 'Random item 1', id: '123512', reason: 'missing_items', }, { name: 'Random item 1', id: '123512', reason: 'missing_items', }, { name: 'Another random item', id: '24122', reason: 'missing_items', }, ], },],
compensatedItems = arr.flatMap(({compensatedItems}) => compensatedItems),
result = Object.values(compensatedItems.reduce((a, {name, ...rest}) => {
(a[name] || (a[name] = {...rest, name, count: 0})).count++;
return a;
}, Object.create(null)));
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
With the flatted array, we can reduce it with your preferred counting logic.