【问题标题】:javascript exclude some values in average calcjavascript在平均计算中排除一些值
【发布时间】:2019-05-22 18:34:02
【问题描述】:

以下是一些数据:

data = [
 {"Age":26,"Level":8},
 {"Age":37,"Level":9},
 {"Age":null,"Level":15},
 {"Age":null,"Level":45}
];

我试图从中计算其属性的平均值:

var avg = {};
  var rows = data.length;
  data.forEach(obj => {
      Object.keys(obj).forEach(k => {
        if(obj[k] != null){
          avg[k] = (avg[k] || 0) + obj[k] / rows;
        }
      });
    });

  return avg;

但问题在于具有null 值的属性的项目,我试图从计算中排除null 值,如果您查看codepen,则有年龄:15.75 而不是 31.5 因为数据的长度始终为 4(并且应该为 2,因为其中 2 个是 null)。如何使长度不包括nulls 的最佳方法是?

【问题讨论】:

  • 如果所有年龄都为空怎么办?那你希望发生什么?
  • 可能写为null

标签: javascript arrays javascript-objects


【解决方案1】:

您可以拥有一个具有嵌套对象的对象,该对象具有两个属性 valuecount

const data = [
 {"Age":26,"Level":8},
 {"Age":37,"Level":9},
 {"Age":null,"Level":15},
 {"Age":null,"Level":45}
];

let avg = {}

data.forEach(x => {
  for(let k in x){
    if(!avg[k]){
      avg[k] = {value:0,count:0};
    }
    if(x[k] !== null){
      avg[k].value += x[k]
      avg[k].count++;
    }
  }
})

avg = Object.fromEntries(Object.entries(avg).map(([k,v]) => ([k,v.value/v.count])))

console.log(avg)

【讨论】:

    【解决方案2】:

    let data = [
    	{"Age": 26, "Level": 8},
    	{"Age": 37, "Level": 9},
    	{"Age": null, "Level": 15},
    	{"Age": null, "Level": 45}
    ];
    
    let averages = data.reduce((values, o) => {
    	Object.entries(o).forEach(([k, v]) => {
    		if (v !== null)
    			values[k] = (values[k] || []).concat(v);
    	});
    	return values;
    }, {});
    
    Object.entries(averages).forEach(([k, vs]) =>
    	averages[k] = vs.reduce((a, b) => a + b) / vs.length);
    
    console.log(averages);

    【讨论】:

      【解决方案3】:

      您可以使用简单的for...offor...in 循环来获取每个非空项目的sumcount。您可以添加get 属性,以根据计数器中的sumcount 属性自动计算平均值

      const data = [{Age:26,Level:8},{Age:37,Level:9},{Age:null,Level:15},{Age:null,Level:45}];
      
      let counter = {}
      
      for (const item of data) {
        for (const key in item) {
          if (item[key] !== null) {
              counter[key] = counter[key] || {
                sum: 0,
                count: 0,
                get average() { return this.sum/this.count }
              };
              counter[key].sum += item[key]
              counter[key].count++
            }
          }
        }
      
        console.log(counter)

      【讨论】:

        【解决方案4】:

        我会这样做:(尚未测试)

        var data = [
            {"Age":26,"Level":8},
            {"Age":37,"Level":9},
            {"Age":null,"Level":15},
            {"Age":null,"Level":45}
        ];
        
        var sum = { "Age": 0, "Level": 0 };
        var average = { "Age": 0, "Level": 0 };
        var sumCount = { "Age": 0, "Level": 0 };
        
        // sum up all objects
        for (var i = 0; i < data.length; i++) {
            Object.keys(data[i]).forEach(function (key) {
                if (data[i][key] == null || data[i][key] == undefined)
                    return;
                sumCount[key]++;
                sum[key] = sum[key] + data[i][key];
            });
        }
        
        // make average object
        Object.keys(average).forEach(function (key) {
            average[key] = sum[key] / sumCount[key];
        });
        

        【讨论】:

          【解决方案5】:

          您可以独立存储每个键的总和和计数。

          var data = [{ "Age": 26, "Level": 8 }, { "Age": 37, "Level": 9 }, { "Age": null, "Level": 15 }, { "Age": null, "Level": 45 }],
              avg = {},
              temp = {};
          
          data.forEach(obj => Object.keys(obj).forEach(k => {
              if (obj[k] === null) return;
              temp[k] = temp[k] || { sum: 0, count: 0 };
              temp[k].sum += obj[k];
              temp[k].count++;
              avg[k] = temp[k].sum / temp[k].count;
          }));
          
          console.log(avg);
          console.log(temp);
          .as-console-wrapper { max-height: 100% !important; top: 0; }

          【讨论】:

          • 我不喜欢每次增加计数时重新计算平均值的方式。这就是为什么我需要每隔几年就购买一台速度更快的笔记本电脑。
          • @Wyck,您可以将计算移到循环之外。无需购买新笔记本电脑。
          【解决方案6】:

          您也可以以相对简洁的方式使用 Array.reduce 并在其中迭代 Object.keys

          var data = [ {"Age":26,"Level":8}, {"Age":37,"Level":9}, {"Age":null,"Level":15}, {"Age":null,"Level":45} ];
          
          let result = data.reduce((r, c) => (Object.keys(c).forEach(k => {
              r[k] = (r[k] || { Sum: 0, Count: 0, Avg: 0 })
              r[k].Sum += c[k] || 0
              r[k].Count += c[k] ? 1 : 0
              r[k].Avg = r[k].Sum / r[k].Count
            }), r), {})
          
          console.log(result)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-10-02
            • 2011-12-04
            • 2021-10-14
            • 1970-01-01
            • 1970-01-01
            • 2020-09-06
            • 2014-12-02
            • 1970-01-01
            相关资源
            最近更新 更多