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

夙愿已清 提交于 2019-12-04 23:41:31

问题


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?


回答1:


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




回答2:


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);



回答3:


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




回答4:


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
})



回答5:


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



来源:https://stackoverflow.com/questions/21819819/summarize-array-of-objects-and-calculate-average-value-for-each-unique-object-na

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!