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

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/


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


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.

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

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! :) :)


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

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

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.


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.



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

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


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

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.


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');
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.