3
votes

javascript exclut certaines valeurs du calcul moyen

Voici quelques données:

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;

à partir desquelles j'essaie de calculer la moyenne de leurs propriétés:

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

mais le problème est dans les éléments qui ont des propriétés avec des valeurs null , où j'essaie d'exclure les valeurs null du calcul, et si vous jetez un oeil à la codepen il y a Âge: 15,75 au lieu de 31,5 car la longueur des données est toujours de 4 (et devrait être de 2 puisque 2 d'entre elles sont nulles ). Quelle serait la meilleure façon d'obtenir la longueur pour ne pas inclure les nulls?


2 commentaires

Et si tous les âges sont nuls? Que voulez-vous qu'il se passe alors?


Ecrire probablement null


6 Réponses :


1
votes

Vous pouvez utiliser un simple pour ... sur et for ... in boucle pour obtenir la somme et count pour chaque non- élément nul. Vous pouvez ajouter un get propriété pour calculer automatiquement la moyenne en fonction des propriétés sum et count dans les données du compteur

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 commentaires

1
votes

Vous pouvez stocker la somme et le nombre de chaque clé indépendamment.

.as-console-wrapper { max-height: 100% !important; top: 0; }
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);


2 commentaires

Je n'aime pas comment cela recalcule la moyenne à chaque fois qu'il incrémente le compte. C'est pourquoi je dois acheter un ordinateur portable plus rapide tous les quelques années.


@Wyck, vous pouvez déplacer le calcul en dehors de la boucle. pas besoin d'acheter un nouvel ordinateur portable.



1
votes

Vous pouvez avoir un objet avec un objet imbriqué qui a deux propriétés value et 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)


0 commentaires

1
votes

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


0 commentaires

1
votes

Je ferais quelque chose comme ceci: (pas encore testé)

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


0 commentaires

0
votes

Vous pouvez également le faire de manière relativement concise avec seulement Array.reduce et à l'intérieur, il suffit de parcourir le 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)


0 commentaires