Cara yang lebih baik untuk menjumlahkan nilai properti dalam array


184

Saya punya sesuatu seperti ini:

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

Sekarang untuk memiliki jumlah total array ini, saya melakukan sesuatu seperti ini:

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

Sangat mudah ketika hanya satu array, tetapi saya memiliki array lain dengan nama properti berbeda yang ingin saya jumlahkan.

Saya akan lebih bahagia jika saya bisa melakukan sesuatu seperti ini:

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

Tapi saya tidak tahu bagaimana harus melalui ini sehingga saya bisa menggunakannya kembali di masa depan seperti ini:

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

Menjawab

Saya memutuskan untuk menggunakan saran @ gruff-bunny, jadi saya menghindari prototyping objek asli (Array)

Saya baru saja melakukan sedikit modifikasi untuk jawabannya memvalidasi array dan nilai untuk menjumlahkan tidak nol, ini adalah implementasi terakhir saya:

$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
Anda dapat memposting Jawaban Anda sebagai jawaban .
Ken Kin

Jawaban:


124

Jawaban yang Diperbarui

Karena semua kerugian dari menambahkan fungsi ke prototipe Array, saya memperbarui jawaban ini untuk memberikan alternatif yang membuat sintaksis mirip dengan sintaks yang awalnya diminta dalam pertanyaan.

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

Jawaban Asli

Karena ini adalah array, Anda dapat menambahkan fungsi ke prototipe Array.

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/


1
terima kasih @ sp00m sekarang saya telah mengubah implementasi saya dengan array.reduce seperti menjawab kasar-kelinci.
nramirez

Anda mungkin perlu melakukan polyfill pada fungsi pengurangan jika Anda perlu mendukung browser lama: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
bottens

Tolong jangan memperpanjang Array.prototypekarena mungkin merusak kode Anda di masa depan. Mengapa memperluas objek asli adalah praktik yang buruk? .
str

@bottens bagaimana jika ada objek null dalam array?
Obby

228

Saya tahu bahwa pertanyaan ini memiliki jawaban yang diterima tetapi saya pikir saya akan ikut serta dengan alternatif yang menggunakan array.reduce , melihat bahwa menjumlahkan array adalah contoh kanonik untuk mengurangi:

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

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

Fiddle


jawaban yang brilian, apakah mungkin untuk menempatkan $scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');di awal fungsi pengontrol?
Mo

Ya jika itu datang setelah fungsi jumlah dibuat.
Gruff Bunny

14
Adakah alasan untuk downvote pada 6 Oktober 2015? Jika ada masalah dengan jawabannya maka silakan tambahkan komentar dan saya akan memperbaikinya. Tidak ada yang belajar dari downvotes anonim.
Gruff Bunny

Ini dapat menghasilkan NaN, jika prop tidak ada (tidak terdefinisi) di salah satu objek dalam array. Saya tidak tahu apakah ini pemeriksaan terbaik, tetapi berhasil untuk kasus saya: function (items, prop) {return items.reduce (function (a, b) {if (! IsNaN (b [prop])) { kembalikan a + b [prop];} else {return a}}, 0); }
claytronicon

131

Hanya mengambil lain, ini adalah apa nativefungsi JavaScript Mapdan Reducedibangun untuk (Peta dan Mengurangi adalah pembangkit tenaga listrik dalam banyak bahasa).

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

Catatan : dengan membuat fungsi-fungsi kecil yang terpisah kita mendapatkan kemampuan untuk menggunakannya lagi.

// 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);untuk memeriksa nomor saja
diEcho

4
Saya hanya akan berdebat dengan nama variabel prevdalam fungsi pengurangan. Bagi saya, itu menyiratkan bahwa Anda mendapatkan nilai sebelumnya dalam array. Tapi sebenarnya itu adalah pengurangan dari semua nilai sebelumnya. Saya suka accumulator, aggregatoratau sumSoFaruntuk kejelasan.
carpiediem

93

Saya selalu menghindari mengubah metode prototipe dan menambah perpustakaan jadi ini solusi saya:

Menggunakan metode mengurangi array Array sudah cukup

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

3
Parameter kedua (yang menentukan nilai awal a) melakukan trik ketika menggunakan reducedengan objek: di iteratorion pertama, atidak akan menjadi objek pertama dari itemsarray, melainkan akan menjadi 0.
Parziphal

Sebagai fungsi: const sumBy = (items, prop) => items.reduce((a, b) => +a + +b[prop], 0); Penggunaan:sumBy(traveler, 'Amount') // => 235
Rafi

2
Sebagai seorang programmer sekolah tua, reducesintaksisnya terlihat sangat tumpul bagi saya. Otak saya masih "secara let total = 0; items.forEach((item) => { total += item.price; });
alami

1
@AndrWeisR Saya suka solusi Anda yang terbaik. Juga penggunaan asli seperti kata buzz yang sulit dijelaskan untuk apa maksudnya. Saya membuat garis kode yang lebih mendasar berdasarkan solusi Anda dan itu bekerja dengan sangat baik. let total = 0; items.forEach(item => total += item.price)
Ian Poston Framer

22

Saya pikir saya akan menjatuhkan dua sen saya pada ini: ini adalah salah satu operasi yang harus selalu berfungsi murni, tidak bergantung pada variabel eksternal. Beberapa sudah memberikan jawaban yang baik, menggunakan reduceadalah cara untuk pergi ke sini.

Karena sebagian besar dari kita sudah mampu menggunakan sintaks ES2015, inilah proposisi saya:

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

Kami membuatnya menjadi fungsi yang tidak dapat diubah saat kami melakukannya. Apa reduceyang dilakukan di sini hanyalah ini: Mulailah dengan nilai 0untuk akumulator, dan tambahkan nilai dari item yang dilingkari saat itu.

Yay untuk pemrograman fungsional dan ES2015! :)


22

Alternatif untuk peningkatan keterbacaan dan penggunaan Mapdan 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);

Fungsi yang dapat digunakan kembali:

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


Gunakan kurangi nilai default yang .reduce(*** => *** + ***, 0);lain tidak ada pada "+1"
FDisk

19

Anda dapat melakukan hal berikut:

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

13

Ini bekerja untuk saya TypeScriptdan 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);

Semoga bermanfaat.


4

Saya tidak yakin ini telah disebutkan. Tapi ada lodash fungsi untuk itu. Cuplikan di bawah ini di mana nilai adalah atribut Anda untuk dijumlahkan adalah 'nilai'.

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

Keduanya akan bekerja.



1

Berikut ini adalah satu-liner menggunakan fungsi panah ES6.

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

Cara menjumlahkan array objek menggunakan 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

Dari berbagai objek

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

Saya sudah menggunakan jquery. Tapi saya pikir cukup intuitif untuk hanya memiliki:

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

Ini pada dasarnya hanya versi singkat dari jawaban @ akhouri.


0

Inilah solusi yang menurut saya lebih fleksibel:

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

Untuk mendapatkan jumlah, gunakan saja seperti itu:

let sum = sumOfArrayWithParameter(someArray, 'someProperty');
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.