Lepszy sposób sumowania wartości właściwości w tablicy

Mam coś takiego:

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

Teraz aby mieć całkowitą ilość tej tablicy robię coś takiego:

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

To proste, gdy jest tylko jedna tablica, ale mam inne tablice o innej nazwie Właściwości, które chciałbym podsumować.

Byłbym szczęśliwszy, gdybym mógł zrobić coś takiego:

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

Ale Nie wiem jak przez to przejść w taki sposób, że mógłbym go ponownie wykorzystać w przyszłości w taki sposób:

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

Odpowiedź

Postanowiłem aby użyć sugestii @ gruff-bunny, więc unikaj prototypowania natywnego obiektu (Array)

Zrobiłem małą modyfikację jego odpowiedzi sprawdzającej tablicę i wartość do sumy nie jest null, to jest moja ostateczna implementacja:

$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);
};
Author: mplungjan, 2014-04-23

9 answers

Ponieważ jest to tablica, możesz dodać funkcję do prototypu tablicy.

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

The Fiddle: http://jsfiddle.net/9BAmj/

 50
Author: bottens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-23 14:53:03

Wiem, że to pytanie ma akceptowaną odpowiedź, ale pomyślałem, że dołączę do alternatywy, która używa tablicy .reduce, ponieważ sumowanie tablicy jest kanonicznym przykładem dla reduce:

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

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

Fiddle

 145
Author: Gruff Bunny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-23 16:03:56

Jeszcze jedno ujęcie, do czego zostały stworzonenatywne funkcje JAVASCRIPT MAPi REDUCE (Map i Reduce to potęgi w wielu językach).

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

Notatka: tworząc oddzielne mniejsze funkcje otrzymujemy możliwość ich ponownego użycia.

// 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 }];

// I changed "Amount" to "amount" to match data.
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.
 46
Author: SoEzPz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-02 15:34:07

Zawsze unikam zmiany metody prototypu i dodawania biblioteki, więc jest to moje rozwiązanie:

Użycie metody reduce Array prototype jest wystarczające

// + operator for casting to Number
items.reduce((a, b) => +a + +b.price, 0);
 24
Author: Eric Marcelino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-03 21:57:53

To jedna z tych operacji, która powinna być zawsze czysto funkcjonalna, nie opierając się na żadnych zewnętrznych zmiennych. Kilku już udzieliło dobrej odpowiedzi, użycie reduce jest sposobem, aby przejść tutaj.

Ponieważ większość z nas może sobie pozwolić na używanie składni ES2015, oto moja propozycja:

const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
Robimy z niej niezmienną funkcję. To, co reduce tutaj robi, to po prostu to: Zacznij od wartości 0 dla akumulatora i dodaj wartość bieżącego zapętlonego elementu do niego.

Yay dla programowania funkcyjnego i ES2015! :)

 17
Author: Ricardo Magalhães,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-15 20:47:49

Nie jestem pewien, czy jeszcze o tym wspomniano. Ale jest do tego Funkcja lodash. Urywek poniżej, gdzie wartością jest atrybut sum to 'value'.

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

Oba będą działać.

 1
Author: Liam Middleton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-19 13:59:19

Może również używać tablicy .prototyp.forEach()

let totalAmount = 0;
$scope.traveler.forEach( data => totalAmount = totalAmount + data.Amount);
return totalAmount;
 1
Author: akhouri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-14 07:24:25

$ scope.podróżnik.map(o= > O. kwota).reduce((a,c)=>a+c);

 1
Author: greenif,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-09 20:56:28

Już używałem jquery. Ale myślę, że jest wystarczająco intuicyjny, aby po prostu mieć:

var total_amount = 0; 
$.each(traveler, function( i, v ) { total_amount += v.Amount ; });
To w zasadzie krótka wersja odpowiedzi @akhouri.
 0
Author: SpiRail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-28 12:17:27