I have an array like so:
var array = [
{
name: \"a\",
value: 1
},
{
name: \"a\",
value: 2
},
{
You can do it with Alasql library with one line of code:
var newArray = alasql('SELECT name, AVG([value]) AS [value] FROM ? GROUP BY name',
[array]);
Here I put "value" in square brackets, because VALUE is a keyword in SQL.
Try this example at jsFiddle
October 2020, I think this is the shortest way (ES6+)
const getAveragesByGroup = (arr, key, val) => {
const average = (a, b, i, self) => a + b[val] / self.length;
return Object.values(
arr.reduce((acc, elem, i, self) => (
(acc[elem[key]] = acc[elem[key]] || {
[key]: elem[key],
[val]: self.filter((x) => x[key] === elem[key]).reduce(average, 0),
}),acc),{})
);
};
console.log(getAveragesByGroup(array, 'name', 'value'))
Try by yourself :)
Here is a ES2015 version, using reduce
let arr = [
{ a: 1, b: 1 },
{ a: 2, b: 3 },
{ a: 6, b: 4 },
{ a: 2, b: 1 },
{ a: 8, b: 2 },
{ a: 0, b: 2 },
{ a: 4, b: 3 }
]
arr.reduce((a, b, index, self) => {
const keys = Object.keys(a)
let c = {}
keys.map((key) => {
c[key] = a[key] + b[key]
if (index + 1 === self.length) {
c[key] = c[key] / self.length
}
})
return c
})
You'll have to loop through the array, computing the sum and counts for each object. Here's a quick implementation:
function average(arr) {
var sums = {}, counts = {}, results = [], name;
for (var i = 0; i < arr.length; i++) {
name = arr[i].name;
if (!(name in sums)) {
sums[name] = 0;
counts[name] = 0;
}
sums[name] += arr[i].value;
counts[name]++;
}
for(name in sums) {
results.push({ name: name, value: sums[name] / counts[name] });
}
return results;
}
Demonstration
Note, this kind of thing can be made much easier if you use a library like Underscore.js:
var averages = _.chain(array)
.groupBy('name')
.map(function(g, k) {
return {
name: k,
value: _.chain(g)
.pluck('value')
.reduce(function(x, y) { return x + y })
.value() / g.length
};
})
.value();
Demonstration
var array = [
{
name: "a",
value: 1
},
{
name: "a",
value: 2
},
{
name: "a",
value: 3
},
{
name: "b",
value: 0
},
{
name: "b",
value: 1
}
];
var sum = {};
for(var i = 0; i < array.length; i++) {
var ele = array[i];
if (!sum[ele.name]) {
sum[ele.name] = {};
sum[ele.name]["sum"] = 0;
sum[ele.name]["count"] = 0;
}
sum[ele.name]["sum"] += ele.value;
sum[ele.name]["count"]++;
}
var result = [];
for (var name in sum) {
result.push({name: name, value: sum[name]["sum"] / sum[name]["count"]});
}
console.log(result);
And a possible solution using ECMA5 (as we seem to be missing one)
var sums = {},
averages = Object.keys(array.reduce(function (previous, element) {
if (previous.hasOwnProperty(element.name)) {
previous[element.name].value += element.value;
previous[element.name].count += 1;
} else {
previous[element.name] = {
value: element.value,
count: 1
};
}
return previous;
}, sums)).map(function (name) {
return {
name: name,
average: this[name].value / this[name].count
};
}, sums);
On jsFiddle