Sum and average Array of Objects in JavaScript

1. The task

Take this array of objects:

[{
  x: 0,
  y: 0,
  z: 0
},
{
  x: 1,
  y: 1,
  z: 1
},
{
  x: 2,
  y: 2,
  z: 2
},
{
  x: 3,
  y: 3,
  z: 3
},
{
  x: 4,
  y: 4,
  z: 4,
}]

Sum the values together and reduce the array to following:

{ x: 10, y: 10, z: 10 }

Additionally, we might want to calculate the average of all the values:

{ x: 2, y: 2, z: 2 }

2. Approaches

Depending on the data structure there are two different ways of approaching the problem

Data structure is known

Assuming we have data structure, where we know the keys:

interface sampleObject {
  x: number
  y: number
  z: number
}

const sample: sampleObject[] = [{ x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }, { x: 2, y: 2, z: 2 }, { x: 3, y: 3, z: 3 }, { x: 4, y: 4, z: 4 }]
const result: sampleObject

(expressed in TypeScript)

Solution

const result = sample.reduce((previous, current, index, array) => {
  return {
    x: previous.x + current.x,
    y: previous.y + current.y,
    z: previous.z + current.z
  }
})

Output

{ x: 10, y: 10, z: 10 }

Explanation

Call the .reduce function, on the sample Array

sample.reduce((previous, current, index, array) => {

Return an Object, in which previous x, y, z values were added to current x, y, z values

  return {
    x: previous.x + current.x,
    y: previous.y + current.y,
    z: previous.z + current.z
  }
})

Data structure is unknown

Assuming we have data structure in which the Object structure is unknown or are in a use-case, where expressing the structure is not necessary or inconvenient:

interface sampleObject {
  [key: string]: number
}

const sample: sampleObject[] = [{ x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }, { x: 2, y: 2, z: 2 }, { x: 3, y: 3, z: 3 }, { x: 4, y: 4, z: 4 }]
const result: sampleObject

(expressed in TypeScript)

Traditional way

const result = {}
sample.forEach((entry) => {
  for (let key in entry) {
    if (!result[key]) result[key] = entry[key]
    else result[key] += entry[key]
  }
})

Output

{ x: 10, y: 10, z: 10 }

Explanation

Create an empty Object, called result:

const result = {}

Iterate each entry in the sample Array:

sample.forEach((entry) => {

Create a for loop to iterate each key in entry Object:

  for (let key in entry) {

If the key is not in the result Object, add it and the entry’s value into the result Object:

    if (!result[key]) result[key] = entry[key]

If the key is in the result Object, add its value to current entry value:

    else result[key] += entry[key]
  }
})

Preferred way

const result = sample.reduce((previous, current, index, array) => {
  Object.keys(current).forEach(key => {
    current[key] += previous[key]
  })

  return current
})

Output

{ x: 10, y: 10, z: 10 }

Explanation

Call the .reduce function, on the sample Array

sample.reduce((previous, current, index, array) => {

Iterate over current Object keys using Object.keys

  Object.keys(current).forEach(key => {

Add current key value to previous key value

    current[key] += previous[key]
  })

Return current Object

  return current
})

4. Calculating the average

Modify previous examples to calculate the average

When data structure is known

const result = sample.reduce((previous, current, index, array) => {
  let x = previous.x + current.x
  let y = previous.y + current.y
  let z = previous.z + current.z

  if (index === array.length - 1) {
    x /= array.length
    y /= array.length
    z /= array.length
  }

  return {x, y, z}
})

Output

{ x: 2, y: 2, z: 2 }

Explanation

 const result = sample.reduce((previous, current, index, array) => {
-  return {
-    x: previous.x + current.x,
-    y: previous.y + current.y,
-    z: previous.z + current.z
+  let x = previous.x + current.x
+  let y = previous.y + current.y
+  let z = previous.z + current.z
+
+  if (index === array.length - 1) {
+    x /= array.length
+    y /= array.length
+    z /= array.length
   }
+
+  return {x, y, z}
 })

(shown as diff)

If current element is the last in the array, divide x, y, z by array length

When data structure is unknown

const result = sample.reduce((previous, current, index, array) => {
  Object.keys(current).forEach(key => {
    current[key] += previous[key]
    if (index === array.length - 1) current[key] /= array.length
  })

  return current
})

Output

{ x: 2, y: 2, z: 2 }

Explanation

 const result = sample.reduce((previous, current, index, array) => {
   Object.keys(current).forEach(key => {
     current[key] += previous[key]
+    if (index === array.length - 1) current[key] /= array.length
   })
 
   return current
 })

(shown as diff)

If current element is the last in the array, divide the current key by array length

5. Bonus: calculate multiple arrays

If you want to calculate on multiple arrays, you can concatenate them using the spread operator

const sample = [...sample_a, ...sample_b]

Now you should be able to understand how to calculate the sum of array of objects and how to calculate the average of array of objects in JavaScript

— Mish Ushakov,