Javascript 求数组数据的平均值

Javascript 求数组数据的平均值,javascript,arrays,algorithm,average,Javascript,Arrays,Algorithm,Average,我一直在研究如何用Javascript实现这个相对简单的操作: 我有一个这样定义的对象列表: [ {id: 1, region: "America", country:"USA", values:[1,2,3,4] }, {id: 2, region: "America", country:"Canada", values:[3,4,5,6] }, {id: 3, region: "Europe", country:"France", values:[1,2,3,4] }

我一直在研究如何用Javascript实现这个相对简单的操作:

我有一个这样定义的对象列表:

[
    {id: 1, region: "America", country:"USA", values:[1,2,3,4] },
    {id: 2, region: "America", country:"Canada", values:[3,4,5,6] },
    {id: 3, region: "Europe", country:"France", values:[1,2,3,4] },
    {id: 4, region: "Europe", country:"Italy", values:[1,2,3,4] },
    {id: 5, region: "Europe", country:"Spain", values:[5,9,1,7] },
    {id: 6, region: "Europe", country:"Germany", values:[1,6,2,8] },
    {id: 7, region: "Europe", country:"Ireland", values:[6,4,6,9]}
      ]
我试图对值字段中包含的数字进行平均,按区域分组。 因此,在上面的列表中,我还有两个元素,一个用于美国,一个用于欧洲,包含平均值:

[
    {id: 1, region: "America", country:"USA", values:[1,2,3,4] },
    {id: 2, region: "America", country:"Canada", values:[3,4,5,6] },
    {id: 3, region: "Europe", country:"France", values:[1,2,3,4] },
    {id: 4, region: "Europe", country:"Italy", values:[1,2,3,4] },
    {id: 5, region: "Europe", country:"Spain", values:[5,9,1,7] },
    {id: 6, region: "Europe", country:"Germany", values:[1,6,2,8] },
    {id: 7, region: "Europe", country:"Ireland", values:[6,4,6,9]},
    {id: 8, region: "America", country:"avg", values:[2,3,4,5]},
    {id: 9, region: "Europe", country:"avg", values:[2.8,4.6,2.8,6.4]}
      ]
你知道怎么做吗? 请记住,要聚合的元素数可能约为10~15,值字段中的数字可能约为150~200 “值”字段包含所有元素的相同数量的值。 有些值可能为null,因此在这种情况下,我需要计算平均值,因为null不是0

我可以做很多循环来扫描所有东西并进行计算,但我想知道是否有更简单、更快的方法来保持良好的性能


解释/示例:
美国的第一个平均值计算如下:

(sum of first value of 'values' for each country with region 'America')
-----------------------------------------------------------------------
            (number of countries with region 'America')
伪代码:

America.avg.values[0] = (USA.values[0] + Canada.values[0]) / 2 /*(1+3)/2 = 2*/;
America.avg.values[1] = (USA.values[1] + Canada.values[1]) / 2 /*(2+4)/2 = 3*/;
...

我只需在整个数组中循环并计算值的平均值,然后在数组中添加一个
avg
属性

var数据=[
{id:1,地区:“美国”,国家:“美国”,价值观:[1,2,3,4]},
{id:2,地区:“美国”,国家:“加拿大”,价值观:[3,4,5,6]},
{id:3,区域:“欧洲”,国家:“法国”,价值观:[1,2,3,4]},
{id:4,区域:“欧洲”,国家:“意大利”,价值观:[1,2,3,4]},
{id:5,区域:“欧洲”,国家:“西班牙”,价值观:[5,9,1,7]},
{id:6,区域:“欧洲”,国家:“德国”,价值观:[1,6,2,8]},
{id:7,区域:“欧洲”,国家:“爱尔兰”,价值观:[6,4,6,9]}
];
forEach(函数(元素、索引、数组){
var总和=0;
element.values.forEach(函数(元素、索引、数组){
总和+=元素;
});
element.avg=总和/element.values.length;
});

控制台日志(数据)您可以使用对象来保持元素的总和和计数,并将每个循环的平均值分配给分组对象

var data=[{id:1,地区:“美国”,国家:“美国”,值:[1,2,3,4]},{id:2,地区:“美国”,国家:“加拿大”,值:[3,4,5,6]},{id:3,地区:“欧洲”,国家:“法国”,值:[1,2,3,4]},{id:4,地区:“欧洲”,国家:“意大利”,值:[1,2,3,4]},{id:5,地区:“欧洲”,国家:“西班牙”,值:[5,9,1,7]},{id:6,地区:“欧洲”,国家:“德国”,价值观:[1,6,2,8]},{id:7,地区:“欧洲”,国家:“爱尔兰”,价值观:[6,4,6,9]};
data.forEach(函数(a,i,aa){
如果(!此[a.区域]){
这个[a.region]={sum:[],count:[],value:[]};
aa.push({id:aa.length+1,region:a.region,country:'avg',value:this[a.region].values});
}
a、 forEach(函数(b,i){
如果(b!==null){
这个[a.区域].sum[i]=(这个[a.区域].sum[i]| | 0)+b;
此[a.region].count[i]=(此[a.region].count[i]| | 0)+1;
此[a.region]。值[i]=此[a.region]。和[i]/此[a.region]。计数[i];
}
},这个);
},Object.create(null));
console.log(数据);

。作为控制台包装{max height:100%!important;top:0;}
您可以这样做:

var data=[{id:1,地区:“美国”,国家:“美国”,值:[1,2,null,4]},{id:2,地区:“美国”,国家:“加拿大”,值:[3,4,5,6]},{id:3,地区:“欧洲”,国家:“法国”,值:[1,2,3,4]},{id:4,地区:“欧洲”,国家:“意大利”,值:[1,2,3,4]},{id:5,地区:“欧洲”,国家:“西班牙”,价值观:[5,9,1,7]},{id:6,地区:“欧洲”,国家:“德国”,价值观:[1,6,2,8]},{id:7,地区:“欧洲”,国家:“爱尔兰”,价值观:[6,4,6,9]}]
//因此区域是可配置的
var地区=[‘美国’、‘欧洲’];
var结果=[];
//对于数据未按id排序的情况。
var lastIndex=Math.max.apply(null,data.map(函数(x){return x.id}))
regions.forEach(函数(r){
var-val=[];
data.forEach(函数(c,i){
如果(c.region===r&&c.values&&c.values.length>0){
c、 forEach(函数(v,i){
如果(!v&&v!==0)返回
val[i]=(val[i]| |[]);
val[i]。推送(v)
})
}
});
var avg=val.map(函数(v){
返回(v.reduce(函数(p,c){returnp+c})/v.length);
})
//不推入数据以防止额外的迭代
结果:推({
id:++lastIndex,
地区:r,
国家:'平均',
数值:平均值
})
});
data=data.concat(结果)

console.log(数据)
减少原始数据,跟踪对象中的中间结果:

  • 对象为它遇到的每个新区域生成一个新的关键点
  • 当考虑区域的第一个数据输入时,存储两件事:
    • 平均值,以第一项值的副本开始
    • 平均值表示的计数,从1开始
  • 当第二项或第n项出现时,使用移动平均公式计算新的平均值
  • 返回结果对象,直到处理完所有条目
  • 将对象转换为两个数据点,并将它们合并为原始阵列
var数据=[
{id:1,地区:“美国”,国家:“美国”,值:[1,2,null,4]},
{id:2,地区:“美国”,国家:“加拿大”,价值观:[3,4,5,6]},
{id:3,区域:“欧洲”,国家:“法国”,价值观:[1,2,3,4]},
{id:4,区域:“欧洲”,国家:“意大利”,价值观:[1,2,3,4]},
{id:5,区域:“欧洲”,国家:“西班牙”,价值观:[5,9,1,7]},
{id:6,区域:“欧洲”,国家:“德国”,价值观:[1,6,2,8]},
{id:7,区域:“欧洲”,国家:“爱尔兰”,价值观:[6,4,6,9]}
];
var avg=数据.reduce(函数(结果,当前){
如果(结果[当前区域]){
var obj=结果[当前区域];
obj.avg=当前值
//映射到移动平均线:
//-位置“i”处的当前平均值表示“计数”样本
.map(函数(v,i){
var data = // your array here

function getArr(data,reg) {
    return data.filter(el => el.region === reg)
               .map(el => el.values)
}

const xpose = x => x[0].map( (c,i) => x.map( r => r[i] ) )

function avgArr(a) {
    a = a.filter(el => el !== null);
    return a.reduce((x,y) => x+y) / a.length;
}

function calcAverages(data) {
    let i = 1 + Math.max.apply(null, data.map( el => el.id )) // max id
    let regions = [...new Set (data.map (a => a.region))]  // unique regions

    regions.forEach( region => {
        data.push( { id: i++,
                     region: region,
                     country: "avg",
                     values: xpose(getArr(data,region)).map(a => avgArr(a))})})

    return data
}

// > calcAverages(data)
//
// ...
//  { id: 8,
//    region: 'America',
//    country: 'avg',
//    values: [ 2, 3, 4, 5 ] },
//  { id: 9,
//    region: 'Europe',
//    country: 'avg',
//    values: [ 2.8, 4.6, 3, 6.4 ] } ]