web-dev-qa-db-fra.com

Faire la somme de toutes les données d'un tableau d'objets dans un nouveau tableau d'objets

J'ai un tableau d'objets qui ressemble à ceci:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}]

et je veux résumer chaque élément du tableau pour produire un tableau comme celui-ci:

var result = [{costOfAirtickets: 4000, costOfHotel: 3200}]

J'ai utilisé une carte et une fonction de réduction, mais je n'ai pu résumer qu'un élément individuel comme suit:

data.map(item => ite.costOfAirtickets).reduce((prev, next)=>prev + next); // 22

Pour le moment, cela produit une valeur unique qui n’est pas ce que je veux comme explication initiale.

Est-il possible de le faire en Javascript ou probablement avec lodash.

25
Dave Kalu

Utiliser for..in pour itérer un objet et reduce pour itérer un tableau

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];

var result = [data.reduce((acc, n) => {
  for (var prop in n) {
    if (acc.hasOwnProperty(prop)) acc[prop] += n[prop];
    else acc[prop] = n[prop];
  }
  return acc;
}, {})]
console.log(result)

17
Chris Li

Utilisez Lodash pour vous simplifier la vie.

const _ = require('lodash')
let keys = ['costOfAirtickets', 'costOfHotel']; 
let results = _.zipObject(keys, keys.map(key => _.sum( _.map(data, key))))
...
{ costOfAirtickets: 4000, costOfHotel: 2200 }

Explication:

  • _.sum(_.map(data, key)): génère la somme de chaque tableau
  • _.zipObject: compresse les résultats avec la somme du tableau
  • utiliser keys.map() pour la somme de chaque clé en tant que _.map ne garantit pas l'ordre.

Documentation:

7
Roopak A Nelliat

Vous n'avez pas besoin de mapper le tableau, vous ne faites que réduire les éléments qu'il contient.

const totalCostOfAirTickets: data.reduce((prev, next) => prev + next.costOfAirTickets, 0)
const totalCostOfHotel: data.reduce((prev, next) => prev + next.costOfHotel, 0)
const totals = [{totalCostOfAirTickets, totalCostOfHotel}]

En une fois, vous pourriez faire quelque chose comme

const totals = data.reduce((prev, next) => { 
    prev.costOfAirTickets += next.costOfAirTickets; 
    prev.costOfHotel += next.costOfHotel; 
}, {costOfAirTickets: 0, costOfHotel: 0})
4
Simon

Une autre solution consisterait à utiliser Map (pas Array.prototype.map) car il présente plusieurs différences notables par rapport aux objets :

var data = [{
  costOfAirtickets: 2500,
  costOfHotel: 1200
}, {
  costOfAirtickets: 1500,
  costOfHotel: 1000
}]

let sums = data.reduce((collection,rcd)=>{
  Object.entries(rcd).forEach(([key,value])=>{
      let sum = collection.get(key) || 0
      collection.set(key, sum + +value)
  })
  return collection
}, new Map())

console.log(...sums.entries())

Explication

Boucle extérieure

La première ci-dessus itère sur votre tableau data en utilisant la méthode reduce. Chaque objet à l'intérieur de celui-ci sera appelé un enregistrement - distingué dans le code via la variable, rcd.

Chaque itération de réduction renvoie une valeur qui est transmise comme premier argument à la prochaine itération de la boucle. Dans ce cas, le paramètre collection contient cet argument, qui correspond à votre ensemble de sommes.

Boucle intérieure

Dans la boucle reduce, chaque paire clé/valeur de l'enregistrement est itérée à l'aide de forEach. Pour obtenir le couple clé/valeur, la méthode Object.entries est utilisée. À l'aide du tableau de déstructuration, ces arguments peuvent être directement affectés aux variables respectives, key et value.

Récupérer/Définir des valeurs

Contrairement à un objet primitif, Map a ses propres méthodes pour obtenir et définir ses entrées à l'aide de get() et set(). Donc, récupérez d'abord la somme précédente en utilisant get(); si elle n'est pas définie, définissez par défaut sur 0, comme le fait le || 0. À ce stade, vous pouvez supposer que la somme précédente est au moins égale à 0 ou supérieure et y ajouter la valeur de la clé actuelle.

Alternatives à la carte

Si vous trouvez que Map est un peu lourd, vous pouvez également utiliser un objet similaire, tel que Set , qui utilise plusieurs des mêmes méthodes (à l'exception de get()), ou vous pouvez également utiliser une primitive. objet (ie {}).

4
Mike

Voici une approche lodash

_(data).flatMap(_.entries).groupBy(0).mapValues(v=>_.sumBy(v, 1)).value()

Il va résumer par toutes les clés uniques.

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];

var res = _(data).flatMap(_.entries).groupBy(0).mapValues(v=>_.sumBy(v, 0)).value();

console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Enveloppez votre résultat dans un [...] ou utilisez un .castArray() à la fin avant de décompresser en utilisant .value() au cas où vous voudriez un tableau comme résultat.

4
Koushik Chatterjee

Pour créer une valeur résultante/réduite, vous devez utiliser la méthode .reduce() à la place de .map():

let data = [
  {costOfAirtickets: 2500, costOfHotel: 1200},
  {costOfAirtickets: 1500, costOfHotel: 1000}
];

let result = data.reduce(
  (a, c) => (Object.keys(c).forEach(k => (a[k] = (a[k] || 0) + c[k])), a), {}
);

console.log(result);

4
Mohammad Usman

Ma réponse simpliste serait comme;

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},
            {costOfAirtickets: 1500, costOfHotel: 1000}],
    res  = data.reduce((p,c) => Object.entries(c).reduce((r,[k,v]) => (r[k]+=v, r), p));
console.log(res);

Remarque sur l'utilisation de .reduce(): Si les éléments du tableau et la valeur accumulée sont du même type, vous pouvez envisager de ne pas utiliser une valeur initiale comme accumulateur et de réduire les éléments précédents (p) et actuels (c). La réduction externe dans l'extrait ci-dessus est de ce type. Toutefois, la réduction interne prend un tableau de paires clé (k) (v) sous la forme [k,v] pour renvoyer un objet; par conséquent, une valeur initiale (p) est essentielle.

Le résultat est la valeur accumulée en tant qu'objet. Si vous en avez besoin dans un tableau, placez-le simplement dans un tableau comme [res].

1
Redu

map l'objet et calculer la somme et le stocker dans un autre.

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var result = [];
var sum = 0;
var costsum = 0;
data.map(function(item, key){
  var cost = item;
  //nsole.log(cost);
  sum = sum + cost.costOfAirtickets;
  costsum = costsum + cost.costOfHotel;

});

result = [{costOfAirtickets:sum, costOfHotel:costsum}];

console.log(result);

1
chintuyadavsara

Vous pouvez utiliser une simple boucle forEach() pour cela:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var res = [];
var tempObj = {};
data.forEach(({costOfAirtickets, costOfHotel}) => {
  tempObj['costOfAirtickets'] = (tempObj['costOfAirtickets'] || 0) + costOfAirtickets;
  tempObj['costOfHotel'] = (tempObj['costOfHotel'] || 0) + costOfHotel;
 });
res.Push(tempObj);
console.log(res);

1
Ankit Agarwal

Essayez d'utiliser réduire seulement comme dans l'extrait ci-dessous. Essayez d'éviter plusieurs itérations. J'espère que l'extrait ci-dessous aide!

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}]

var total = data.reduce(function (result,value,key) {
result['costOfAirtickets'] = result['costOfAirtickets']  + value['costOfAirtickets'];
result['costOfHotel'] = result['costOfHotel']  + value['costOfHotel'];

return result},{costOfAirtickets:0,costOfHotel:0});

console.log(total)

1
CRayen

Vous pouvez réduire le tableau en prenant un objet pour la somme.

var data = [{ costOfAirtickets: 2500, costOfHotel: 1200 }, { costOfAirtickets: 1500, costOfHotel: 1000 }],
    keys = ['costOfAirtickets', 'costOfHotel'],
    sum = data.reduce((r, o) => {
        keys.forEach(k => r[k] += o[k]);
        return r;
    }, Object.assign(...keys.map(k => ({ [k]: 0 }))));

console.log(sum);

1
Nina Scholz

C’est l’approche la plus facile à laquelle je puisse penser

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var sum ={};
for(var obj in data){
  for(var ele in data[obj]){
    if(!data[obj].hasOwnProperty(ele)) continue;
      if(sum[ele] === undefined){
        sum[ele] = data[obj][ele];
      }else{
        sum[ele] = sum[ele] + data[obj][ele];
      }
  }

}
var arr = [sum];
console.log(arr);
1
Armando Prieto

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];

var result = [data.reduce((acc, n) => {
  for (var prop in n) {
    if (acc[prop]) acc[prop] += n[prop];
    else acc[prop] = n[prop];
  }
  return acc;
}, {})]
console.log(result)

0
asma khatoon

Lodash 

Utiliser lodashréduire et _.mergeWith _ ceci est un one-liner:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]

var result = _.reduce(data, (r,c) => _.mergeWith(r, c, (o = 0, s) => o + s), {})

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

ES6 uniquement

Si vous ne voulez PAS transformer le tableau d'origine, vous pouvez utiliser ES6 réduire , Object.entries et pourEach comme ceci:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]

// One liner
var result1 = data.reduce((r, c) =>
  !Object.entries(c).forEach(([key, value]) => r[key] = (r[key] || 0) + value) && r, {})

// More readable
var result2 = data.reduce((r, c) => {
  Object.entries(c).forEach(([key, value]) => r[key] = (r[key] || 0) + value)
  return r
}, {})

console.log(result1)
console.log(result2)

Si nous ne nous soucions pas de mutating le tableau initial data, nous pouvons alors avoir une solution one-liner:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]

data.reduce((r, c) => !Object.entries(c).forEach(([key,value]) => r[key] += value) && r)

console.log(data[0])

Plus lisible:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]

data.reduce((r, c) => {
  Object.entries(c).forEach(([key, value]) => r[key] += value)
  return r
})

console.log(data[0])

La seule différence entre les exemples en mutation et ceux en mutation est la valeur initiale pour le reduce (et aussi le fait qu'avec la mutation, nous utilisons l'indice 0 comme un accumulateur pour les sommes). Dans les mutants, il n'y a pas de initial value; dans les autres, on commence par un objet littéral vide.

si vous voulez que le résultat soit un tableau spécifique, renvoyez [data] pour les exemples en mutation et [result] pour les exemples purs.

0
Akrion