web-dev-qa-db-de.com

Summiere alle Daten in einem Array von Objekten in ein neues Array von Objekten

Ich habe ein Array von Objekten, das so aussieht:

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

und ich möchte jedes Element im Array zusammenfassen, um ein Array wie folgt zu erzeugen:

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

Ich habe eine Map- und Reduction-Funktion verwendet, aber ich konnte nur ein einzelnes Element wie folgt summieren:

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

Im Moment erzeugt dies einen einzigen Wert, den ich nicht als erste Erklärung möchte.

Gibt es eine Möglichkeit, dies in Javascript oder wahrscheinlich mit lodash zu tun?.

25
Dave Kalu

Verwenden Sie for..in zur Iteration des Objekts und reduce zur Iteration des Arrays

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

Verwenden Sie Lodash, um Ihr Leben zu vereinfachen.

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

Erläuterung:

  • _.sum(_.map(data, key)): generiert die Summe jedes Arrays
  • _.zipObject: Zippt die Ergebnisse mit der Arraysumme
  • die Verwendung von keys.map() für die Summe jedes Schlüssels als _.map garantiert keine Bestellung.

Dokumentation:

7

Sie müssen das Array nicht zuordnen, Sie reduzieren lediglich die darin enthaltenen Elemente.

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

Mit einem Mal könnten Sie so etwas tun

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

Eine andere Lösung wäre die Verwendung von Map (not Array.prototype.map), da es einige bemerkenswerte Unterschiede zu Objekten hat :

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

Erläuterung

Äußere Schleife

Das obige erste iteriert über Ihr data-Array mit der reduce-Methode. Jedes Objekt innerhalb dieses Objekts werde ich als Datensatz bezeichnen - im Code durch die Variable rcd unterschieden.

Bei jeder reduzierten Iteration wird ein Wert zurückgegeben, der als erstes Argument an die nächste Iteration der Schleife übergeben wird. In diesem Fall enthält der Parameter collection dieses Argument, bei dem es sich um Ihre Summen handelt.

Innere Schleife

Innerhalb der reduce-Schleife wird jedes Schlüssel/Wert-Paar des Datensatzes mit forEach durchlaufen. Um das Schlüssel/Wert-Paar zu erhalten, wird die Object.entries-Methode verwendet. Durch die Zerstörung von Arrays können diese Argumente direkt den jeweiligen Variablen key und value zugewiesen werden.

Werte abrufen/einstellen

Im Gegensatz zu einem primitiven Objekt verfügt Map über eigene Methoden, um die Einträge mithilfe von get() und set() abzurufen und festzulegen. Rufen Sie also zuerst die vorherige Summe mit get() ab. Wenn diese nicht festgelegt ist, wird standardmäßig 0 verwendet. Dies ist die Funktion von || 0. An diesem Punkt können Sie davon ausgehen, dass die vorherige Summe mindestens 0 oder größer ist, und den aktuellen Schlüsselwert hinzufügen.

Alternativen zur Karte

Wenn Sie feststellen, dass Map etwas hartnäckig ist, können Sie auch ein ähnliches Objekt wie Set verwenden, das viele der gleichen Methoden hat (außer get()), oder Sie können auch ein Grundelement verwenden Objekt (dh {}).

4
Mike

Hier ist ein lodash-Ansatz

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

Es wird nach allen eindeutigen Schlüsseln summiert.

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>

Wickeln Sie Ihr Ergebnis in einen [...] oder verwenden Sie am Ende eine .castArray(), bevor Sie das Paket mit .value() auspacken, falls Sie ein Array als Ergebnis wünschen.

4

Um einen resultierenden/reduzierten Wert zu erstellen, sollten Sie die .reduce()-Methode anstelle von .map() verwenden:

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

Meine vereinfachende Antwort wäre:

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

Ein Hinweis zur Verwendung von .reduce(): Wenn die Array-Elemente und der akkumulierte Wert vom selben Typ sind, können Sie in Betracht ziehen, keinen Anfangswert als Akkumulator zu verwenden, und reduzieren Sie die Werte mit den vorherigen (p) und aktuellen (c) Elementen. Die äußere Verkleinerung in dem obigen Ausschnitt ist von diesem Typ. Für das innere Verkleinern wird jedoch ein Array von Schlüsselpaaren (k) (v) als [k,v] verwendet, um ein Objekt zurückzugeben. Daher ist ein Anfangswert (p) unbedingt erforderlich.

Das Ergebnis ist der akkumulierte Wert als Objekt. Wenn Sie es in einem Array benötigen, legen Sie es einfach in ein Array wie [res].

1
Redu

map das Objekt und berechnet die Summe und speichert sie in einer anderen.

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

Sie können dafür eine einfache forEach()-Schleife verwenden:

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

Verwenden Sie nur wie im folgenden Snippet verkleinern. Vermeiden Sie mehrere Iterationen. Hoffe das untenstehende Snippet hilft!

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

Sie können das Array verkleinern, indem Sie ein Objekt zum Summieren verwenden.

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

Dies ist der einfachste Ansatz, den ich mir vorstellen kann

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 

Mit lodashverkleinern und _.mergeWith ist dies ein Einzeiler:

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>

Nur ES6

Wenn Sie wollen NICHT mutieren das ursprüngliche Array _, können Sie ES6 verkleinern , Object.entries und forEach wie folgt verwenden:

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)

Wenn wir uns nicht für mutating das ursprüngliche data-Array interessieren, können wir eine Ein-Liner-Lösung haben:

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

Lesbarer:

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

Der einzige Unterschied zwischen den mutierenden und nicht mutierenden Beispielen ist der Anfangswert für die reduce (und auch die Tatsache, dass wir mit der Mutation den 0-Index als Akkumulator für die Summen verwenden). Bei den mutierenden gibt es keinen initial value, bei den anderen beginnen wir mit leeren Objektliteralen.

wenn das Ergebnis ein Array sein soll, geben Sie [data] für die mutierenden Beispiele und [result] für die reinen Beispiele zurück.

0
Akrion