0

I am trying to iterate an object and display the average for each key inside the object.

Say I have:

data = {
  totals: {
    item1: {
      time: 15,
      speed: 20,
      amount: 12,
      units: 29
    },
    item2: {
      time: 3,
      speed: 75,
      amount: 14,
      units: 3
    },
    item3: {
      time: 19,
      speed: 4,
      amount: 44,
      units: 365
    }
  }
}

What is the best way to create an average of those values like this:

averages = {
  time: 12,
  speed: 33,
  amount: 40,
  units: 132
}

I know to divide the total of each key's value by the total items, but I am struggling to find a good way to iterate each item and add the totals up. The items will be dynamically created depending on the entries for each account.

Is using a for .. in loop the best way? If so how would I use that to accomplish this? something like below?

function findAverage() {
  const averages = {
    time: 0,
    speed: 0,
    amount: 0,
    units: 0
  }

  const totalItems = Object.keys(data.totals).length 

  for (item in data.totals) {
    averages.time += item.time;
    averages.speed += item.speed;
    averages.amount += item.amount;
    averages.units += item.units;
  }

  averages.time = averages.time / totalItems;
  averages.speed = averages.speed / totalItems;
  averages.amount = averages.amount / totalItems;
  averages.units = averages.units / totalItems;

  return averages;
}

Is there a better way to go about this problem? Am I totally off in what I am trying to do here?

1
  • It is late for me but how about for (items in data.totals) { for (item in items) { averages[item] += items[item] } } Commented Oct 3, 2017 at 19:33

3 Answers 3

3

Instead of loops you can use Object.keys and reduce method on array

function calculateAverage(totals) {
  const items = Object.keys(totals).reduce((result, item) => result.concat(totals[item]), [])
  const itemsCount = items.length;
   
  const metricsTotals = items.reduce((sums, item) => {
    sums.time += item.time
    sums.speed += item.speed
    sums.amount += item.amount
    sums.units += item.units
    return sums
  }, { time: 0, speed: 0, amount: 0, units: 0})

  return Object.keys(metricsTotals).reduce((average, metric) => {
    average[metric] = Math.floor(metricsTotals[metric] / itemsCount)
    return average
  }, {})
}

var data = {
  totals: {
    item1: {
      time: 15,
      speed: 20,
      amount: 12,
      units: 29
    },
    item2: {
      time: 3,
      speed: 75,
      amount: 14,
      units: 3
    },
    item3: {
      time: 19,
      speed: 4,
      amount: 44,
      units: 365
    }
  }
}


const averages= calculateAverage(data.totals)
console.log(averages)

Sign up to request clarification or add additional context in comments.

1 Comment

After some modification to fit my real code this worked perfectly. Thank you so much.
1

You could take the wanted properties and the object and iterate and take then part of the lnght for adding to the average.

var data = { totals: { item1: { time: 15, speed: 20, amount: 12, units: 29 }, item2: { time: 3, speed: 75, amount: 14, units: 3 }, item3: { time: 19, speed: 4, amount: 44, units: 365 } } },
    averages = {},
    keys = ['time', 'speed', 'amount', 'units'];

keys.forEach(function (k) {
    averages[k] = 0;
});

Object.keys(data.totals).forEach(function (l, _, ll) {
    keys.forEach(function (k) {
        averages[k] += data.totals[l][k] / ll.length;
    });
});

// flooring if neccessary
keys.forEach(function (k) {
    averages[k] = Math.floor(averages[k]);
});


console.log(averages);

1 Comment

you just forgot about Math.floor
1

So if you need more performance you have to use for loop. For loop is faster then forEach and forEach is faster then for in loop. Here you can find performance benchmarks https://jsperf.com/for-vs-foreach/75

This code as an example for unlimited amount of items and unlimited amount of values.

"use strict";

let data = {
  totals: {
item1: {
  time: 15,
  speed: 20,
  amount: 12,
  units: 29
},
item2: {
  time: 3,
  speed: 75,
  amount: 14,
  units: 3
},
item3: {
  time: 19,
  speed: 4,
  amount: 44,
  units: 365
}
  }
};

let items = Object.keys(data.totals);
let max = items.length;
let keys = Object.keys(data.totals[items[0]]);
let averages = {};

for (let i = 0, max = keys.length; i < max; i++) {
    averages[keys[i]] = 0;
}

for (let i = 0; i < max; i++) {
    for (let j = 0, max2 = keys.length; j < max2; j++) {
        averages[keys[j]] += data.totals[items[i]][keys[j]] || 0;
    }
}

for (let i = 0, max2 = keys.length; i < max2; i++) {
    averages[keys[i]] = Math.floor(averages[keys[i]]/max);
}

console.log(averages);

Also topicstarter has a mistake

averages = { time: 12, speed: 33, amount: 40, units: 132 }

amount value can't be 40 (12 + 14 + 44 => 70 / 3 = 23)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.