what is the most efficient way to group by multiple object properties? It groups by category
and then by group
.
I have detailed my implementation using a single array reduce which I will push into an array (expected output). I am not sure how to conditionally push to sources
array which is created within the reduce.
Without using lodash groupBy or third party. I was also thinking of filtering by a key I create e.g.
const key = `${category}-${group}`;
const items = [
{
"name": "Halloumi",
"group": "Cheese",
"category": "Dairy"
},
{
"name": "Mozzarella",
"group": "Cheese",
"category": "Dairy"
}
];
// my current implementation
const groupedItems = items.reduce((map, item) => {
const { category, name, group } = item;
if (map.has(category)) {
map.get(category).push({
name,
group,
});
} else {
map.set(category, [
{
name,
group,
},
]);
}
return map;
}, new Map());
console.log(Object.fromEntries(groupedItems));
// Another attempt
const groupedItems2 = items.reduce((map, item) => {
const { category, group, name } = item;
acc[category] = acc[category] || { category, themes: [] };
const source = {
id,
name
};
const totalSources = [source].length;
const uniqueSources = [...new Set([source])].length;
acc[category].themes.push({
theme,
totalSources,
uniqueSources,
sources: [source],
});
return acc;
return map;
}, {});
console.log(Object.entries(groupedItems2));
// expected output
[
{
"category": "Dairy",
"groups": [
{
"group": "Cheese",
"totalSources": 2,
"sources": [
{
"name": "Halloumi"
},
{
"name": "Mozzarella"
}
]
}
]
}
]
CodePudding user response:
You need a two-level map.
There are many ways to do that. Here is one:
const items = [{"name": "Halloumi","group": "Cheese","category": "Dairy"},{"name": "Mozzarella","group": "Cheese","category": "Dairy"}];
const dict = {};
for (const {name, group, category} of items) {
((dict[category] ??= {})[group] ??= []).push({name});
}
const categories = Object.entries(dict).map(([category, groups]) => ({
category,
groups: Object.entries(groups).map(([group, sources]) => ({
group,
totalSources: sources.length,
sources
}))
}));
console.log(categories);