JavaScript исключает некоторые значения в среднем расчете - PullRequest
3 голосов
/ 22 мая 2019

Вот некоторые данные:

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). Как было бы наилучшим способом получить длину, не включающую null s?

Ответы [ 6 ]

1 голос
/ 22 мая 2019

Я бы сделал что-то вроде этого: (еще не проверено)

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];
});
1 голос
/ 22 мая 2019

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);
1 голос
/ 22 мая 2019

Вы можете иметь объект с вложенным объектом, который имеет два свойства value и count

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)
1 голос
/ 22 мая 2019

Вы можете хранить сумму и считать для каждого ключа независимо.

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; }
1 голос
/ 22 мая 2019

Вы можете использовать простой цикл for...of и for...in, чтобы получить sum и count для каждого ненулевого элемента. Вы можете добавить свойство get, чтобы автоматически вычислять среднее значение на основе свойств sum и count в счетчике

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)
0 голосов
/ 23 мая 2019

Вы также можете сделать это относительно кратким способом, просто 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)
...