web-dev-qa-db-fra.com

Comment additionner les valeurs d'un objet JavaScript?

Je voudrais résumer les valeurs d'un objet.

Je suis habitué à python où ce serait juste:

sample = { 'a': 1 , 'b': 2 , 'c':3 };
summed =  sum(sample.itervalues())     

Le code suivant fonctionne, mais c'est beaucoup de code:

function obj_values(object) {
  var results = [];
  for (var property in object)
    results.Push(object[property]);
  return results;
}

function list_sum( list ){
  return list.reduce(function(previousValue, currentValue, index, array){
      return previousValue + currentValue;
  });
}

function object_values_sum( obj ){
  return list_sum(obj_values(obj));
}

var sample = { a: 1 , b: 2 , c:3 };
var summed =  list_sum(obj_values(a));
var summed =  object_values_sum(a)

Est-ce que je manque quelque chose d'évident, ou est-ce juste comme ça?

51

Vous pouvez tout mettre dans une fonction:

function sum( obj ) {
  var sum = 0;
  for( var el in obj ) {
    if( obj.hasOwnProperty( el ) ) {
      sum += parseFloat( obj[el] );
    }
  }
  return sum;
}
    
var sample = { a: 1 , b: 2 , c:3 };
var summed = sum( sample );
console.log( "sum: "+summed );


Pour le plaisir, voici une autre implémentation utilisant Object.keys() et Array.reduce() (la prise en charge du navigateur ne devrait plus être un gros problème):

function sum(obj) {
  return Object.keys(obj).reduce((sum,key)=>sum+parseFloat(obj[key]||0),0);
}
let sample = { a: 1 , b: 2 , c:3 };

console.log(`sum:${sum(sample)}`);

Mais cela semble être beaucoup plus lent: jsperf.com

52
Sirko

Cela peut être aussi simple que cela:

const sumValues = obj => Object.values(obj).reduce((a, b) => a + b);

Citant MDN:

La méthode Object.values() renvoie un tableau des valeurs de propriété énumérables propres à un objet donné, dans le même ordre que celui fourni par une boucle for...in (la différence étant qu'une boucle for-in énumère également des propriétés dans la chaîne de prototypes).

de Object.values() sur MDN

La méthode reduce() applique une fonction à un accumulateur et à chaque valeur du tableau (de gauche à droite) pour le réduire à une valeur unique.

de Array.prototype.reduce() sur MDN

Vous pouvez utiliser cette fonction comme ça:

sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5

Notez que ce code utilise certaines fonctionnalités ECMAScript qui ne sont pas prises en charge par certains navigateurs plus anciens (comme IE). Vous devrez peut-être utiliser Babel pour compiler votre code.

57

Une boucle for régulière est assez concise:

var total = 0;

for (var property in object) {
    total += object[property];
}

Vous devrez peut-être ajouter object.hasOwnProperty si vous avez modifié le prototype.

17
Blender

Si vous utilisez lodash, vous pouvez faire quelque chose comme:

_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 })) 
16
Leon

Une raison pour laquelle vous n'utilisez pas simplement une boucle for...in

var sample = { a: 1 , b: 2 , c:3 };
var summed = 0;

for (var key in sample) {
    summed += sample[key];
};

http://jsfiddle.net/vZhXs/

10
jbabey

Honnêtement, étant donné nos "temps modernes", j'adopterais une approche de programmation fonctionnelle chaque fois que possible, comme ceci:

const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);

Notre accumulateur acc, commençant par la valeur 0, accumule toutes les valeurs en boucle de notre objet. Cela présente l’avantage supplémentaire de ne pas dépendre de variables internes ou externes; c'est une fonction constante pour ne pas être écrasé accidentellement ... gagnant pour ES2015!

8
Ricardo Magalhães

Vous pouvez maintenant utiliser la fonction reduce et obtenir la somme.

const object1 = { 'a': 1 , 'b': 2 , 'c':3 }

console.log(Object.values(object1).reduce((a, b) => a + b, 0));
4
Krishnadas PC

Je suis un peu en retard pour le parti, cependant, si vous avez besoin d’une solution plus robuste et plus flexible, voici ma contribution. Si vous souhaitez additionner uniquement une propriété spécifique dans un combo objet/tableau imbriqué, ainsi que réaliser d'autres méthodes d'agrégat, voici une petite fonction que j'utilisais dans un projet React:

var aggregateProperty = function(obj, property, aggregate, shallow, depth) {
    //return aggregated value of a specific property within an object (or array of objects..)

    if ((typeof obj !== 'object' && typeof obj !== 'array') || !property) {
        return;
    }

    obj = JSON.parse(JSON.stringify(obj)); //an ugly way of copying the data object instead of pointing to its reference (so the original data remains unaffected)
    const validAggregates = [ 'sum', 'min', 'max', 'count' ];
    aggregate = (validAggregates.indexOf(aggregate.toLowerCase()) !== -1 ? aggregate.toLowerCase() : 'sum'); //default to sum

    //default to false (if true, only searches (n) levels deep ignoring deeply nested data)
    if (shallow === true) {
        shallow = 2;
    } else if (isNaN(shallow) || shallow < 2) {
        shallow = false;
    }

    if (isNaN(depth)) {
        depth = 1; //how far down the rabbit hole have we travelled?
    }

    var value = ((aggregate == 'min' || aggregate == 'max') ? null : 0);
    for (var prop in obj) {
        if (!obj.hasOwnProperty(prop)) {
            continue;
        }

        var propValue = obj[prop];
        var nested = (typeof propValue === 'object' || typeof propValue === 'array');
        if (nested) {
            //the property is an object or an array

            if (prop == property && aggregate == 'count') {
                value++;
            }

            if (shallow === false || depth < shallow) {
                propValue = aggregateProperty(propValue, property, aggregate, shallow, depth+1); //recursively aggregate nested objects and arrays
            } else {
                continue; //skip this property
            }
        }

        //aggregate the properties value based on the selected aggregation method
        if ((prop == property || nested) && propValue) {
            switch(aggregate) {
                case 'sum':
                    if (!isNaN(propValue)) {
                        value += propValue;
                    }
                    break;
                case 'min':
                    if ((propValue < value) || !value) {
                        value = propValue;
                    }
                    break;
                case 'max':
                    if ((propValue > value) || !value) {
                        value = propValue;
                    }
                    break;
                case 'count':
                    if (propValue) {
                        if (nested) {
                            value += propValue;
                        } else {
                            value++;
                        }
                    }
                    break;
            }
        }
    }

    return value;
}

Il est récursif, non ES6, et il devrait fonctionner dans la plupart des navigateurs semi-modernes. Vous l'utilisez comme ceci:

const onlineCount = aggregateProperty(this.props.contacts, 'online', 'count');

Répartition des paramètres:

obj = un objet ou un tableau
property = la propriété des objets/tableaux imbriqués sur lesquels vous souhaitez exécuter la méthode d'agrégation
agrégé = la méthode d'agrégat (somme, min, max ou nombre)
shallow = peut être défini sur true/false ou sur une valeur numérique
depth = devrait être laissé nul ou indéfini (il est utilisé pour suivre les rappels récursifs suivants)

Shallow peut être utilisé pour améliorer les performances si vous savez que vous n'avez pas besoin de rechercher des données profondément imbriquées. Par exemple, si vous avez le tableau suivant:

[
    {
        id: 1,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    {
        id: 2,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    {
        id: 3,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    ...
]

Si vous souhaitez éviter de parcourir en boucle la propriété otherData, car la valeur que vous allez agréger n'est pas imbriquée aussi profondément, vous pouvez définir peu profond la valeur true.

1
user5487386

A ramda one liner:

import {
 compose, 
 sum,
 values,
} from 'ramda'

export const sumValues = compose(sum, values);

Utilisez: const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });

0
Damian Green

Je suis tombé sur cette solution de @jbabey en essayant de résoudre un problème similaire. Avec un peu de modification, j'ai bien compris. Dans mon cas, les clés d’objet sont des nombres (489) et des chaînes ("489"). Par conséquent, pour résoudre ce problème, chaque clé est analysée. Le code suivant fonctionne:

var array = {"nR": 22, "nH": 7, "totB": "2761", "nSR": 16, "htRb": "91981"}
var parskey = 0;
for (var key in array) {
    parskey = parseInt(array[key]);
    sum += parskey;
};
return(sum);
0
Olu Adabonyan