Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Most efficient method to groupby on an array of objects - JavaScript
Grouping arrays of objects is a common task in JavaScript data processing. We'll explore efficient methods to group objects by single or multiple properties and aggregate values.
Sample Data
Let's start with an array of objects representing project phases, steps, and tasks:
const arr = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
console.log("Original data:", arr.length, "records");
Original data: 8 records
Method 1: Using reduce() with Map (Most Efficient)
This method uses nested Maps to handle multiple grouping levels efficiently:
const groupBy = (array, groups, valueKey) => {
const map = new Map();
groups = [].concat(groups); // Ensure groups is always an array
return array.reduce((acc, val) => {
groups.reduce((accu, value, ind, { length }) => {
let child;
if (accu.has(val[value])) {
return accu.get(val[value]);
}
if (ind + 1 === length) {
child = Object.assign(
...groups.map(value => ({ [value]: val[value] })),
{ [valueKey]: 0 }
);
acc.push(child);
} else {
child = new Map();
}
accu.set(val[value], child);
return child;
}, map)[valueKey] += +val[valueKey];
return acc;
}, []);
};
// Group by single property
console.log("Grouped by Phase:");
console.log(groupBy(arr, 'Phase', 'Value'));
Grouped by Phase:
[ { Phase: 'Phase 1', Value: 50 }, { Phase: 'Phase 2', Value: 130 } ]
Method 2: Using Object.groupBy() (ES2024)
Modern JavaScript provides Object.groupBy() for simple grouping scenarios:
// Simple grouping by Phase (without aggregation)
const groupedByPhase = Object.groupBy(arr, item => item.Phase);
console.log("Object.groupBy() result:");
console.log(Object.keys(groupedByPhase));
// To aggregate values, we need additional processing
const aggregated = Object.entries(groupedByPhase).map(([phase, items]) => ({
Phase: phase,
Value: items.reduce((sum, item) => sum + parseInt(item.Value), 0)
}));
console.log("Aggregated:");
console.log(aggregated);
Object.groupBy() result:
[ 'Phase 1', 'Phase 2' ]
Aggregated:
[ { Phase: 'Phase 1', Value: 50 }, { Phase: 'Phase 2', Value: 130 } ]
Multi-Level Grouping Example
Group by both Phase and Step to create nested groupings:
// Group by multiple properties
console.log("Grouped by Phase and Step:");
const multiGrouped = groupBy(arr, ['Phase', 'Step'], 'Value');
console.log(multiGrouped);
Grouped by Phase and Step:
[
{ Phase: 'Phase 1', Step: 'Step 1', Value: 15 },
{ Phase: 'Phase 1', Step: 'Step 2', Value: 35 },
{ Phase: 'Phase 2', Step: 'Step 1', Value: 55 },
{ Phase: 'Phase 2', Step: 'Step 2', Value: 75 }
]
Performance Comparison
| Method | Time Complexity | Multi-level Support | Browser Support |
|---|---|---|---|
| reduce() + Map | O(n) | Yes | All modern browsers |
| Object.groupBy() | O(n) | Limited | ES2024 (limited) |
| forEach loops | O(n) | Manual implementation | All browsers |
Key Benefits
The Map-based approach offers several advantages:
// Flexible - handles any number of grouping levels
const singleGroup = groupBy(arr, 'Phase', 'Value');
const doubleGroup = groupBy(arr, ['Phase', 'Step'], 'Value');
const tripleGroup = groupBy(arr, ['Phase', 'Step', 'Task'], 'Value');
console.log("Single level groups:", singleGroup.length);
console.log("Double level groups:", doubleGroup.length);
console.log("Triple level groups:", tripleGroup.length);
Single level groups: 2 Double level groups: 4 Triple level groups: 8
Conclusion
The reduce() with Map approach provides the most efficient and flexible solution for grouping arrays of objects. It handles multiple grouping levels and aggregates values in a single pass with O(n) complexity.
