Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Summarize array of objects and calculate average value for each unique object name

I have an array like so:

var array = [
     {
       name: "a",
       value: 1 
     },
     {
       name: "a",
       value: 2 
     },
     {
       name: "a",
       value: 3 
     },
     {
       name: "b",
       value: 0 
     },
     {
       name: "b",
       value: 1 
     }
 ];

And I need an array like this:

var newarray = [
     {
       name: "a",
       value: 2
     },
     {
       name: "b",
       value: 0.5
     }
 ]

Where the new array has each unique name as an object with the average value.

Is there an easy way to accomplish this?

like image 724
user3317337 Avatar asked Feb 17 '14 02:02

user3317337


People also ask

How do you find the unique values of an array of objects?

One way to get distinct values from an array of JavaScript objects is to use the array's map method to get an array with the values of a property in each object. Then we can remove the duplicate values with the Set constructor. And then we can convert the set back to an array with the spread operator.

How do you find the average value of an array of elements?

Average is the sum of array elements divided by the number of elements. Examples : Input : arr[] = {1, 2, 3, 4, 5} Output : 3 Sum of the elements is 1+2+3+4+5 = 15 and total number of elements is 5.


4 Answers

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

like image 159
p.s.w.g Avatar answered Nov 14 '22 23:11

p.s.w.g


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);
like image 22
wander Avatar answered Nov 14 '22 21:11

wander


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

like image 36
agershun Avatar answered Nov 14 '22 22:11

agershun


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
})
like image 21
Iban Dominguez Noda Avatar answered Nov 14 '22 21:11

Iban Dominguez Noda