Bir dizideki özellik değerini toplamanın daha iyi yolu


184

Böyle bir şey var:

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

Şimdi bu dizinin toplam Tutarı için ben böyle bir şey yapıyorum:

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

Ne zaman sadece bir dizi kolay, ama ben toplamak istiyorum farklı bir özellik adı ile diğerleri diziler var.

Böyle bir şey yapabilirsem daha mutlu olurdum:

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

Ama bunu gelecekte nasıl tekrar kullanabileceğimden nasıl geçeceğimi bilmiyorum:

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

Cevap

@ Gruff-bunny önerisini kullanmaya karar verdim, bu yüzden yerel nesneyi prototiplemekten kaçınıyorum (Dizi)

Ben sadece dizi doğrulayan cevabında küçük bir değişiklik yaptım ve toplamı değer boş değil, bu benim son uygulama:

$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
Cevabınızı cevap olarak gönderebilirsiniz .
Ken Kin

Yanıtlar:


124

Güncellenmiş Yanıt

Array prototipine bir işlev eklemenin tüm dezavantajları nedeniyle, sözdizimini soruda başlangıçta istenen sözdizimine benzeyen bir alternatif sağlamak için bu yanıtı güncelliyorum.

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

Orijinal Yanıt

Bir dizi olduğu için Array prototipine bir işlev ekleyebilirsiniz.

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

Keman: http://jsfiddle.net/9BAmj/


1
teşekkürler @ sp00m şimdi ben gruff-bunny yanıt gibi array.reduce ile benim uygulama değişti.
nramirez

Daha eski tarayıcıları desteklemeniz gerekiyorsa azaltma işlevini
çoklu doldurmanız gerekebilir

Array.prototypeİleride kodunuzu kırabileceğinden lütfen uzatmayın . Yerel nesneleri genişletmek neden kötü bir uygulamadır? .
str

@bottens dizide boş bir nesne varsa ne olur?
Obby

228

Bu sorunun kabul edilmiş bir cevabı olduğunu biliyorum ama bir dizi özetlemek azaltmak için kanonik bir örnek olduğunu görerek, array.reduce kullanan bir alternatif ile yonga düşündüm :

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

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

Fiddle


parlak cevap, $scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');denetleyici işlevinin başına koymak mümkün mü?
Mo.

Sum işlevi oluşturulduktan sonra gelirse evet.
Gruff Bunny

14
6 Ekim 2015'teki düşüşün sebebi var mı? Cevabınızla ilgili bir sorun varsa, lütfen bir yorum ekleyin ve düzelteceğim. Kimse anonim inişlerden öğrenemez.
Gruff Bunny

Prop dizideki nesnelerden birinde yoksa (tanımsız) NaN ile sonuçlanabilir. Bu en iyi kontrol olup olmadığını bilmiyorum, ama benim durumum için çalıştı: function (items, prop) {return items.reduce (function (a, b) {if (! İsNaN (b [prop]))) { a + b [prop];} başka {dönüş a}}, 0); }
claytronicon

130

Sadece başka bir şey, nativeJavaScript işlevlerinin yapıldığı Mapve Reduceoluşturulduğu şeydir (Harita ve Azalt birçok dilde güç merkezleridir).

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

Not : ayrı küçük işlevler yaparak bunları tekrar kullanma olanağına sahibiz.

// 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);numarayı kontrol etmek için
diEcho

4
Yalnızca prevazaltma işlevinde değişkenin adı ile tartışırım . Bana göre bu, dizideki önceki değeri aldığınız anlamına gelir. Ama gerçekten önceki tüm değerlerin azalması. Sevdiğim accumulator, aggregatorya sumSoFarnetlik için.
carpiediem

93

Ben her zaman prototip yöntemini değiştirmek ve bu benim çözüm bu yüzden kütüphane eklemek kaçının:

Array dizisi prototip yöntemini kullanmak yeterlidir

// + operator for casting to Number
items.reduce((a, b) => +a + +b.price, 0);

3
Nesnelerle birlikte akullanıldığında ikinci parametre (başlangıç ​​değerini belirleyen ) hile yapar reduce: ilk yinelemede, dizinin ailk nesnesi itemsolmayacak, bunun yerine olacaktır 0.
Parziphal

Bir fonksiyon olarak: const sumBy = (items, prop) => items.reduce((a, b) => +a + +b[prop], 0); Kullanım:sumBy(traveler, 'Amount') // => 235
Rafi

2
Eski bir okul programcısı olarak, reducesözdizimi bana tamamen aykırı görünüyor. Beynim hala "doğal olarak" bunu daha iyi anlıyor:let total = 0; items.forEach((item) => { total += item.price; });
AndrWeisR

1
@AndrWeisR Çözümü en çok seviyorum. Ayrıca, ne anlama geldiğini pek açıklayamayan bir vızıltı kelimesi olduğu için yerli kullanımı. Çözümünüze dayalı daha temel bir kod satırı yaptım ve harika çalıştı. let total = 0; items.forEach(item => total += item.price)
Ian Poston Framer

22

İki sentimi buna bırakacağımı düşündüm: Bu, herhangi bir dış değişkene dayanmadan, her zaman tamamen işlevsel olması gereken işlemlerden biridir. Birkaç kişi zaten iyi bir cevap verdi, kullanma reduceburaya gitmek için bir yoldur.

Çoğumuz zaten ES2015 sözdizimini kullanmaya gücümüz olduğundan, benim önerim:

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

Biz işteyken onu değişmez bir işlev haline getiriyoruz. Ne reducedeğeriyle Başlangıç: Burada yapıyor basitçe şudur 0akümülatör ve buna cari İlmekledi öğenin değerini ekleyin.

Fonksiyonel programlama ve ES2015 için Yay! :)


22

Geliştirilmiş okunabilirlik ve kullanma için alternatif Mapve 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);

Yeniden kullanılabilir fonksiyonu:

const calculateSum = (obj, field) => obj
  .map(items => items.attributes[field])
  .reduce((prev, curr) => prev + curr, 0);

Mükemmel dostum, "+1"
Mayank Pandeyz

Varsayılan değeri azaltın, .reduce(*** => *** + ***, 0);başkalarının "+1" değerinde eksik olduğunu kullanın
FDisk

19

Aşağıdakileri yapabilirsiniz:

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

13

Benim için çalışıyor TypeScriptve 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);

Umarım faydalıdır.


4

Henüz bahsedilmediğinden emin değilim. Ama bunun için bir sadakat işlevi var. Değerin, toplam özniteliğiniz olduğu snippet, 'değer' dir.

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

Her ikisi de işe yarayacak.



1

İşte ES6 ok işlevlerini kullanan bir astar.

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

Javascript kullanarak nesne dizisini toplama

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

Nesne dizisinden

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

Zaten jquery kullanıyordum. Ama bence sahip olacak kadar sezgisel:

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

Bu temelde @ akhouri'nin cevabının sadece kısa bir versiyonudur.


0

İşte daha esnek bulduğum bir çözüm:

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

Toplamı almak için basitçe şöyle kullanın:

let sum = sumOfArrayWithParameter(someArray, 'someProperty');
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.