Besserer Weg, einen Eigenschaftswert in einem Array zu summieren

182

Ich habe so etwas:

$scope.traveler = [
            {  description: 'Senior', Amount: 50},
            {  description: 'Senior', Amount: 50},
            {  description: 'Adult', Amount: 75},
            {  description: 'Child', Amount: 35},
            {  description: 'Infant', Amount: 25 },
];

Um nun einen Gesamtbetrag dieses Arrays zu haben, mache ich ungefähr so:

$scope.totalAmount = function(){
       var total = 0;
       for (var i = 0; i < $scope.traveler.length; i++) {
              total = total + $scope.traveler[i].Amount;
            }
       return total;
}

Es ist einfach, wenn es nur ein Array gibt, aber ich habe andere Arrays mit einem anderen Eigenschaftsnamen, den ich zusammenfassen möchte.

Ich wäre glücklicher, wenn ich so etwas tun könnte:

$scope.traveler.Sum({ Amount });

Aber ich weiß nicht, wie ich das so durchgehen soll, dass ich es in Zukunft so wiederverwenden könnte:

$scope.someArray.Sum({ someProperty });

Antworten

Ich habe mich für den @ gruff-bunny-Vorschlag entschieden, um das Prototyping eines nativen Objekts (Array) zu vermeiden.

Ich habe nur eine kleine Änderung an seiner Antwort vorgenommen, um das Array zu validieren, und der zu summierende Wert ist nicht null. Dies ist meine endgültige Implementierung:

$scope.sum = function (items, prop) {
    if (items == null) {
        return 0;
    }
    return items.reduce(function (a, b) {
        return b[prop] == null ? a : a + b[prop];
    }, 0);
};
nramirez
quelle
2
Sie können Ihre Antwort als Antwort veröffentlichen .
Ken Kin

Antworten:

124

Aktualisierte Antwort

Aufgrund aller Nachteile des Hinzufügens einer Funktion zum Array-Prototyp aktualisiere ich diese Antwort, um eine Alternative bereitzustellen, bei der die Syntax der ursprünglich in der Frage angeforderten Syntax ähnelt.

class TravellerCollection extends Array {
    sum(key) {
        return this.reduce((a, b) => a + (b[key] || 0), 0);
    }
}
const traveler = new TravellerCollection(...[
    {  description: 'Senior', Amount: 50},
    {  description: 'Senior', Amount: 50},
    {  description: 'Adult', Amount: 75},
    {  description: 'Child', Amount: 35},
    {  description: 'Infant', Amount: 25 },
]);

console.log(traveler.sum('Amount')); //~> 235

Ursprüngliche Antwort

Da es sich um ein Array handelt, können Sie dem Array-Prototyp eine Funktion hinzufügen.

traveler = [
    {  description: 'Senior', Amount: 50},
    {  description: 'Senior', Amount: 50},
    {  description: 'Adult', Amount: 75},
    {  description: 'Child', Amount: 35},
    {  description: 'Infant', Amount: 25 },
];

Array.prototype.sum = function (prop) {
    var total = 0
    for ( var i = 0, _len = this.length; i < _len; i++ ) {
        total += this[i][prop]
    }
    return total
}

console.log(traveler.sum("Amount"))

Die Geige: http://jsfiddle.net/9BAmj/

bottens
quelle
1
danke @ sp00m jetzt habe ich meine Implementierung mit array.reduce geändert, genau wie gruff-bunny geantwortet hat.
Nramirez
Möglicherweise müssen Sie die Reduzierungsfunktion mehrfach
ausfüllen,
Bitte verlängern Sie nicht, Array.prototypeda dies Ihren Code in Zukunft beschädigen könnte. Warum ist das Erweitern nativer Objekte eine schlechte Praxis? .
Str
@bottens was ist, wenn das Array ein Nullobjekt enthält?
Obby
228

Ich weiß, dass diese Frage eine akzeptierte Antwort hat, aber ich dachte, ich würde eine Alternative einschlagen , die array.reduce verwendet , da das Summieren eines Arrays das kanonische Beispiel für Reduzieren ist:

$scope.sum = function(items, prop){
    return items.reduce( function(a, b){
        return a + b[prop];
    }, 0);
};

$scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');

Fiddle

Gruff Bunny
quelle
brillante Antwort, ist es möglich, $scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');am Anfang der Controller-Funktion zu setzen?
Mo.
Ja, wenn es kommt, nachdem die Summenfunktion erstellt wurde.
Gruff Bunny
14
Gibt es einen Grund für die Ablehnung am 6. Oktober 2015? Wenn es ein Problem mit der Antwort gibt, fügen Sie bitte einen Kommentar hinzu und ich werde ihn korrigieren. Niemand lernt aus anonymen Abstimmungen.
Gruff Bunny
Dies kann zu NaN führen, wenn die Requisite in einem der Objekte im Array nicht vorhanden (undefiniert) ist. Ich weiß nicht, ob dies die beste Prüfung ist, aber es hat in meinem Fall funktioniert: function (items, prop) {return items.reduce (Funktion (a, b) {if (! IsNaN (b [prop])) { return a + b [prop];} else {return a}}, 0); }
Claytronicon
129

Nur ein weiteres nehmen, ist es das , was nativeJavaScript - Funktionen Mapund Reducewurden gebaut (Karte und Elektrizitätskraftwerke reduzieren in vielen Sprachen).

var traveler = [{description: 'Senior', Amount: 50},
                {description: 'Senior', Amount: 50},
                {description: 'Adult', Amount: 75},
                {description: 'Child', Amount: 35},
                {description: 'Infant', Amount: 25}];

function amount(item){
  return item.Amount;
}

function sum(prev, next){
  return prev + next;
}

traveler.map(amount).reduce(sum);
// => 235;

// or use arrow functions
traveler.map(item => item.Amount).reduce((prev, next) => prev + next);

Hinweis : Durch die Erstellung separater kleinerer Funktionen können wir diese wieder verwenden.

// Example of reuse.
// Get only Amounts greater than 0;

// Also, while using Javascript, stick with camelCase.
// If you do decide to go against the standards, 
// then maintain your decision with all keys as in...

// { description: 'Senior', Amount: 50 }

// would be

// { Description: 'Senior', Amount: 50 };

var travelers = [{description: 'Senior', amount: 50},
                {description: 'Senior', amount: 50},
                {description: 'Adult', amount: 75},
                {description: 'Child', amount: 35},
                {description: 'Infant', amount: 0 }];

// Directly above Travelers array I changed "Amount" to "amount" to match standards.

function amount(item){
  return item.amount;
}

travelers.filter(amount);
// => [{description: 'Senior', amount: 50},
//     {description: 'Senior', amount: 50},
//     {description: 'Adult', amount: 75},
//     {description: 'Child', amount: 35}];
//     Does not include "Infant" as 0 is falsey.
SoEzPz
quelle
4
return Number(item.Amount);nur um die Nummer zu überprüfen
diEcho
4
Ich würde nur mit dem Namen der Variablen previn der Reduktionsfunktion streiten . Für mich bedeutet dies, dass Sie den vorherigen Wert im Array erhalten. Aber es ist wirklich die Reduzierung aller vorherigen Werte. Ich mag accumulator, aggregatoroder sumSoFarfür Klarheit.
Carpiediem
92

Ich vermeide es immer, die Prototypmethode zu ändern und eine Bibliothek hinzuzufügen, daher ist dies meine Lösung:

Die Verwendung der Reduce Array-Prototypmethode ist ausreichend

// + operator for casting to Number
items.reduce((a, b) => +a + +b.price, 0);
Eric Marcelino
quelle
3
Der zweite Parameter (der den Anfangswert von bestimmt a) macht den Trick bei der Verwendung reducemit Objekten: In der ersten Iteratorion awird nicht das erste Objekt des itemsArrays sein, sondern es wird sein 0.
Parziphal
Als Funktion: const sumBy = (items, prop) => items.reduce((a, b) => +a + +b[prop], 0); Verwendung:sumBy(traveler, 'Amount') // => 235
Rafi
2
Als Programmierer der alten Schule erscheint reducemir die Syntax völlig stumpf. Mein Gehirn versteht das immer noch "nativ" besser:let total = 0; items.forEach((item) => { total += item.price; });
AndrWeisR
1
@AndrWeisR Ich mag Ihre Lösung am besten. Auch die Verwendung von Native, da es so ein Modewort ist, dass kaum erklärt wird, wofür es gedacht ist. Ich habe eine noch einfachere Codezeile basierend auf Ihrer Lösung erstellt und sie hat großartig funktioniert. let total = 0; items.forEach(item => total += item.price)
Ian Poston Framer
22

Ich dachte, ich würde meine zwei Cent dafür verlieren: Dies ist eine dieser Operationen, die immer rein funktional sein sollten und sich nicht auf externe Variablen stützen sollten. Einige gaben bereits eine gute Antwort, mit reduceist der Weg hierher zu gehen.

Da sich die meisten von uns die Verwendung der ES2015-Syntax bereits leisten können, ist hier mein Vorschlag:

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

Wir machen es zu einer unveränderlichen Funktion, während wir dabei sind. Was reducehier getan wird, ist einfach Folgendes: Beginnen Sie mit einem Wert von 0für den Akkumulator und addieren Sie den Wert des aktuell geloopten Elements.

Yay für funktionale Programmierung und ES2015! :) :)

Ricardo Magalhães
quelle
21

Alternative für verbesserte Lesbarkeit und Verwendung Mapund Reduce:

const traveler = [
    {  description: 'Senior', amount: 50 },
    {  description: 'Senior', amount: 50 },
    {  description: 'Adult', amount: 75 },
    {  description: 'Child', amount: 35 },
    {  description: 'Infant', amount: 25 },
];

const sum = traveler
  .map(item => item.amount)
  .reduce((prev, curr) => prev + curr, 0);

Wiederverwendbare Funktion:

const calculateSum = (obj, field) => obj
  .map(items => items.attributes[field])
  .reduce((prev, curr) => prev + curr, 0);
Codingbamby
quelle
Perfekter Kumpel, "+1"
Mayank Pandeyz
Verwenden Sie den Standardwert reduzieren, .reduce(*** => *** + ***, 0);anderen fehlte "+1"
FDisk
19

Sie können Folgendes tun:

$scope.traveler.map(o=>o.Amount).reduce((a,c)=>a+c);
greenif
quelle
13

Es funktioniert für mich in TypeScriptund JavaScript:

let lst = [
     { description:'Senior', price: 10},
     { description:'Adult', price: 20},
     { description:'Child', price: 30}
];
let sum = lst.map(o => o.price).reduce((a, c) => { return a + c });
console.log(sum);

Ich hoffe es ist nützlich.

AminRostami
quelle
4

Ich bin mir nicht sicher, ob dies bereits erwähnt wurde. Dafür gibt es aber eine Lodash- Funktion. Das folgende Snippet, in dem value Ihr Attribut für die Summe ist, ist 'value'.

_.sumBy(objects, 'value');
_.sumBy(objects, function(o) { return o.value; });

Beides wird funktionieren.

Liam Middleton
quelle
2

kann auch Array.prototype.forEach () verwenden

let totalAmount = 0;
$scope.traveler.forEach( data => totalAmount = totalAmount + data.Amount);
return totalAmount;
Akhouri
quelle
1

Hier ist ein Einzeiler mit ES6-Pfeilfunktionen.

const sumPropertyValue = (items, prop) => items.reduce((a, b) => a + b[prop], 0);

// usage:
const cart_items = [ {quantity: 3}, {quantity: 4}, {quantity: 2} ];
const cart_total = sumPropertyValue(cart_items, 'quantity');
Steve Breese
quelle
1

So summieren Sie ein Objektarray mit Javascript

const traveler = [
  {  description: 'Senior', Amount: 50},
  {  description: 'Senior', Amount: 50},
  {  description: 'Adult', Amount: 75},
  {  description: 'Child', Amount: 35},
  {  description: 'Infant', Amount: 25 }
];

const traveler = [
    {  description: 'Senior', Amount: 50},
    {  description: 'Senior', Amount: 50},
    {  description: 'Adult', Amount: 75},
    {  description: 'Child', Amount: 35},
    {  description: 'Infant', Amount: 25 },
];
function sum(arrayData, key){
   return arrayData.reduce((a,b) => {
  return {Amount : a.Amount + b.Amount}
})
}
console.log(sum(traveler))
`

kvimalkr55
quelle
1

Aus einer Reihe von Objekten

function getSum(array, column)
  let values = array.map((item) => parseInt(item[column]) || 0)
  return values.reduce((a, b) => a + b)
}

foo = [
  { a: 1, b: "" },
  { a: null, b: 2 },
  { a: 1, b: 2 },
  { a: 1, b: 2 },
]

getSum(foo, a) == 3
getSum(foo, b) == 6
Franz
quelle
0

Ich habe bereits jquery verwendet. Aber ich denke, es ist intuitiv genug, um nur zu haben:

var total_amount = 0; 
$.each(traveler, function( i, v ) { total_amount += v.Amount ; });

Dies ist im Grunde nur eine Kurzversion von @ akhouris Antwort.

SpiRail
quelle
0

Hier ist eine Lösung, die ich flexibler finde:

function sumOfArrayWithParameter (array, parameter) {
  let sum = null;
  if (array && array.length > 0 && typeof parameter === 'string') {
    sum = 0;
    for (let e of array) if (e && e.hasOwnProperty(parameter)) sum += e[parameter];
  }
  return sum;
}

Um die Summe zu erhalten, verwenden Sie sie einfach so:

let sum = sumOfArrayWithParameter(someArray, 'someProperty');
Philippe Genois
quelle