汇总对象数组并计算每个唯一对象名称的平均值

时间:2014-02-17 02:41:32

标签: javascript arrays unique average

我有一个像这样的数组:

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

我需要一个像这样的数组:

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

新数组的每个唯一名称都是具有平均值的对象。

有没有一种简单的方法可以实现这一目标?

6 个答案:

答案 0 :(得分:6)

您必须遍历数组,计算每个对象的总和和计数。这是一个快速实现:

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

注意,如果您使用像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

答案 1 :(得分: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);

答案 2 :(得分:1)

这是ES2015版本,使用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
})

答案 3 :(得分:0)

使用ECMA5的可能解决方案(因为我们似乎缺少一个)

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

jsFiddle

答案 4 :(得分:0)

您可以使用Alasql库使用一行代码执行此操作:

var newArray = alasql('SELECT name, AVG([value]) AS [value] FROM ? GROUP BY name',
                       [array]);

这里我将“value”放在方括号中,因为VALUE是SQL中的关键字。

在jsFiddle

尝试this example

答案 5 :(得分:0)

2020年10月,我认为这是最短的方法(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'))

自己尝试:)