2014-02-17 78 views
4

计算平均值我有一个数组,像这样:总结对象的数组,每个唯一对象名称

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

凡新数组每个唯一名称作为具有平均值的对象。

有没有简单的方法来完成这个?

+0

你只是想知道'了'和'B'? –

+0

a和b只是例子。我的数组将具有比a和b更多的名称。我的值如何不正确? a的值为1,2和3. 1 + 2 + 3 = 6,a有3个值,所以6/3 = 2。b的值为0和1. 0 + 1 = 1,有2个值b,所以1/2 = 0.5。 – user3317337

+0

@ user3317337:对不起,那是我的错误 - 我虽然第三个是“b”,而不是“a”。 –

回答

5

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

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

+0

谢谢。我很欣赏快速反应和示范。 – user3317337

+1

我不知道下划线版本“更容易”。它需要理解*链*,* groupBy *,* map *,* pluck *,* value *和* reduce * plus需要一个合适的* reduce *函数。我敢打赌它也比POJS版本慢得多(可以更简洁)。 ;-) – RobG

+0

@RobG公平点。如果你喜欢功能性编程策略,这会更容易。我主要想提供一个替代方案。 –

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

0

您可以Alasql库一行代码做到这一点:

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

在这里,我把“价值”在方括号中,因为VALUE是SQL中的关键字。

尝试this example在的jsfiddle

0

下面是一个ES2015版,采用减少

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