How to Group and Find Average of Objects in Nested Arrays?

Working with nested arrays is a common task in JavaScript. One frequent requirement is grouping objects by a specific property and calculating the average value for each group.

In this guide, we’ll explore the most effective way to group data and compute averages using modern JavaScript.

Example Problem

Suppose you have an array containing nested arrays of student scores:

const data = [
  [
    { subject: 'Math', score: 80 },
    { subject: 'Science', score: 90 }
  ],
  [
    { subject: 'Math', score: 70 },
    { subject: 'Science', score: 85 }
  ],
  [
    { subject: 'Math', score: 95 }
  ]
];

The goal is to calculate the average score for each subject.

Expected output:

{
  Math: 81.67,
  Science: 87.5
}

Step 1: Flatten the Nested Arrays

The easiest way is to flatten the nested structure first.

const flattened = data.flat();

Result:

[
  { subject: 'Math', score: 80 },
  { subject: 'Science', score: 90 },
  { subject: 'Math', score: 70 },
  { subject: 'Science', score: 85 },
  { subject: 'Math', score: 95 }
]

Step 2: Group and Aggregate

Use reduce() to collect totals and counts.

const grouped = flattened.reduce((acc, item) => {
  if (!acc[item.subject]) {
    acc[item.subject] = {
      total: 0,
      count: 0
    };
  }

  acc[item.subject].total += item.score;
  acc[item.subject].count++;

  return acc;
}, {});

Result:

{
  Math: { total: 245, count: 3 },
  Science: { total: 175, count: 2 }
}

Step 3: Calculate Averages

Convert totals into averages.

const averages = Object.fromEntries(
  Object.entries(grouped).map(([subject, stats]) => [
    subject,
    stats.total / stats.count
  ])
);

console.log(averages);

Output:

{
  Math: 81.66666666666667,
  Science: 87.5
}

Complete Solution

const averages = Object.fromEntries(
  Object.entries(
    data.flat().reduce((acc, item) => {
      if (!acc[item.subject]) {
        acc[item.subject] = { total: 0, count: 0 };
      }

      acc[item.subject].total += item.score;
      acc[item.subject].count++;

      return acc;
    }, {})
  ).map(([subject, stats]) => [
    subject,
    stats.total / stats.count
  ])
);

console.log(averages);

Formatting the Result

To display averages with two decimal places:

const formatted = Object.fromEntries(
  Object.entries(averages).map(([key, value]) => [
    key,
    Number(value.toFixed(2))
  ])
);

console.log(formatted);

Output:

{
  Math: 81.67,
  Science: 87.50
}

Performance Considerations

For small and medium-sized datasets, using flat() and reduce() provides excellent readability.

See also  How can I get the list of files in a directory in a shell script?

For extremely large datasets, you may prefer a single-pass loop to avoid creating an intermediate flattened array. However, for most applications, the difference is negligible and the cleaner code is usually worth it.

Infographic

Conclusion

The best approach to group objects in nested arrays and calculate averages is to:

  1. Flatten the nested arrays using flat().
  2. Group data with reduce().
  3. Track totals and counts.
  4. Calculate averages using Object.entries() and Object.fromEntries().

This approach is concise, easy to maintain, and works well with modern JavaScript applications.

Previous Article

Best Approach to Filter a Map to an Object in JavaScript?

Next Article

How Can I Generate Dynamic JSON-LD Schema Markup for Thousands of Shopify Product Pages?

Write a Comment

Leave a Comment

Your email address will not be published. Required fields are marked *

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.
Pure inspiration, zero spam ✨