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);
};
nramirez
sumber
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/

botol
sumber
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

Gruff Bunny
sumber
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.
SoEzPz
sumber
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);
Eric Marcelino
sumber
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! :)

Ricardo Magalhães
sumber
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);
codingbamby
sumber
Sobat
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);
greenif
sumber
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.

AminRostami
sumber
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.

Liam Middleton
sumber
2

juga dapat menggunakan Array.prototype.forEach ()

let totalAmount = 0;
$scope.traveler.forEach( data => totalAmount = totalAmount + data.Amount);
return totalAmount;
akhouri
sumber
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');
Steve Breese
sumber
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))
`

kvimalkr55
sumber
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
Franz
sumber
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.

SpiRail
sumber
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');
Philippe Genois
sumber