Reputation: 408
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?
Upvotes: 0
Views: 78
Reputation: 503
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)
Upvotes: 1
Reputation: 2203
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)
Upvotes: 3
Reputation: 386654
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);
Upvotes: 1