Refactor Complex Data Aggregation and Filtering in JavaScript
Improve the quality and maintainability of a long, nested JavaScript function that processes and aggregates data from a complex array of objects while preserving its original behavior and performance.
Challenge prompt
You are given a function `processUserData` that takes an array of user activity objects and returns a summary report. The existing function works correctly but is difficult to read, deeply nested, and inefficient in places. Your challenge is to refactor this function to improve readability, maintainability, and efficiency without changing its output. Requirements: - Break down complex logic into smaller reusable functions. - Remove unnecessary nested loops and if statements. - Use modern ES6+ features where appropriate. - Ensure that the behavior and output remain exactly the same. Analyze the provided code, refactor it, then test to verify the result matches the original output.
Guidance
- • Identify repeated patterns and extract helper functions for clarity.
- • Use array methods like map, filter, reduce to simplify iteration and aggregation.
- • Replace nested conditional statements with early returns or guard clauses.
- • Consider using destructuring, default parameters, and meaningful variable names.
Hints
- • Look for opportunities to use reduce instead of manual accumulators.
- • Avoid mutating the input data for purity and side-effect prevention.
- • Split one big function into multiple smaller functions with clear responsibilities.
Starter code
function processUserData(users) {
const result = {};
for (let i = 0; i < users.length; i++) {
const user = users[i];
if (user && user.activities && user.activities.length > 0) {
for (let j = 0; j < user.activities.length; j++) {
const activity = user.activities[j];
if (activity.type) {
if (!result[activity.type]) {
result[activity.type] = { count: 0, users: new Set() };
}
result[activity.type].count++;
result[activity.type].users.add(user.id);
}
}
}
}
// Convert sets to counts
const summary = {};
for (const type in result) {
if (Object.prototype.hasOwnProperty.call(result, type)) {
summary[type] = {
totalActivities: result[type].count,
uniqueUsers: result[type].users.size
};
}
}
return summary;
}Expected output
{"login":{"totalActivities":7,"uniqueUsers":3},"purchase":{"totalActivities":3,"uniqueUsers":2},"logout":{"totalActivities":5,"uniqueUsers":3}}
Core concepts
Challenge a Friend
Send this duel to someone else and see if they can solve it.