Bagaimana cara menjumlahkan nilai sebuah objek JavaScript?

87

Saya ingin menjumlahkan nilai suatu objek.

Saya terbiasa dengan python di mana itu hanya akan:

sample = { 'a': 1 , 'b': 2 , 'c':3 };
summed =  sum(sample.itervalues())     

Kode berikut berfungsi, tetapi banyak kode:

function obj_values(object) {
  var results = [];
  for (var property in object)
    results.push(object[property]);
  return results;
}

function list_sum( list ){
  return list.reduce(function(previousValue, currentValue, index, array){
      return previousValue + currentValue;
  });
}

function object_values_sum( obj ){
  return list_sum(obj_values(obj));
}

var sample = { a: 1 , b: 2 , c:3 };
var summed =  list_sum(obj_values(a));
var summed =  object_values_sum(a)

Apakah saya melewatkan sesuatu yang jelas, atau apakah memang begini adanya?

Jonathan Vanasco
sumber

Jawaban:

77

Anda bisa meletakkan semuanya dalam satu fungsi:

function sum( obj ) {
  var sum = 0;
  for( var el in obj ) {
    if( obj.hasOwnProperty( el ) ) {
      sum += parseFloat( obj[el] );
    }
  }
  return sum;
}
    
var sample = { a: 1 , b: 2 , c:3 };
var summed = sum( sample );
console.log( "sum: "+summed );


Demi kesenangan, berikut adalah implementasi lain yang menggunakan Object.keys()dan Array.reduce()(dukungan browser seharusnya tidak menjadi masalah besar lagi):

function sum(obj) {
  return Object.keys(obj).reduce((sum,key)=>sum+parseFloat(obj[key]||0),0);
}
let sample = { a: 1 , b: 2 , c:3 };

console.log(`sum:${sum(sample)}`);

Tapi ini tampaknya jauh lebih lambat: jsperf.com

Sirko
sumber
kembali sum + parseFloat (obj [key] || 0) untuk memeriksa falsey atau null / nilai-nilai kosong
sumit
1
Kerja bagus menyoroti perbedaan kinerja di antara solusi. Meskipun Object.keys().reducetampilannya jauh lebih elegan, ini 60% lebih lambat.
micnguyen
104

Ini bisa sesederhana itu:

const sumValues = obj => Object.values(obj).reduce((a, b) => a + b);

Mengutip MDN:

The Object.values()Metode mengembalikan array sendiri nilai properti enumerable suatu objek tertentu, dalam urutan yang sama seperti yang disediakan oleh for...inlingkaran (perbedaan adalah bahwa untuk-sifat lingkaran menyebutkan dalam rantai prototipe juga).

dari Object.values()di MDN

The reduce()Metode berlaku fungsi terhadap akumulator dan setiap nilai dari array (dari kanan kiri ke) untuk mengurangi ke nilai tunggal.

dari Array.prototype.reduce()di MDN

Anda dapat menggunakan fungsi ini seperti itu:

sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5

Perhatikan bahwa kode ini menggunakan beberapa fitur ECMAScript yang tidak didukung oleh beberapa browser lama (seperti IE). Anda mungkin perlu menggunakan Babel untuk mengompilasi kode Anda.

Michał Perłakowski
sumber
3
Ini mengharuskan Anda menarik perpustakaan 60K hanya untuk memilikinya Object.values(), yang akan diisi dengan forloop di setiap browser selain Firefox. Bahkan tanpa polyfill, ini 4x lebih lambat dari forloop biasa bagi saya.
Blender
10
@Blender Anda tetap perlu menggunakan Babel jika Anda ingin menggunakan salah satu fitur ECMAScript baru dan masih mendukung browser lama. Selain itu, jika seseorang mengunjungi pertanyaan ini misalnya setelah 2 tahun, browser modern mungkin akan menerapkannya Object.values()hingga saat itu.
Michał Perłakowski
Jawaban yang diterima memiliki pendekatan yang sangat mirip, tetapi fungsi yang diteruskan reducetampaknya sedikit lebih mudah dilakukan. Apakah Anda sengaja mengabaikan penguraian?
Cerbrus
@ Cerbrus Saya berasumsi bahwa semua nilai dalam objek itu adalah angka.
Michał Perłakowski tanggal
12
@ Blender Sepertinya saya benar - satu setengah tahun berlalu, dan Object.values()didukung oleh semua browser modern .
Michał Perłakowski
25

Jika Anda menggunakan lodash, Anda dapat melakukan sesuatu seperti

_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 })) 
Leon
sumber
20

Putaran biasa forcukup ringkas:

var total = 0;

for (var property in object) {
    total += object[property];
}

Anda mungkin harus menambahkan object.hasOwnPropertyjika Anda memodifikasi prototipe.

Blender
sumber
15

Sejujurnya, mengingat "zaman modern" kami, saya akan menggunakan pendekatan pemrograman fungsional bila memungkinkan, seperti:

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

Akumulator kita acc, dimulai dengan nilai 0, mengumpulkan semua nilai loop dari objek kita. Ini memiliki keuntungan tambahan karena tidak bergantung pada variabel internal atau eksternal; ini adalah fungsi konstan sehingga tidak akan tertimpa secara tidak sengaja ... menang untuk ES2015!

Ricardo Magalhães
sumber
13

Sekarang Anda dapat menggunakan reducefungsi dan mendapatkan jumlahnya.

const object1 = { 'a': 1 , 'b': 2 , 'c':3 }

console.log(Object.values(object1).reduce((a, b) => a + b, 0));

Krishnadas PC
sumber
12

Adakah alasan Anda tidak hanya menggunakan for...inloop sederhana ?

var sample = { a: 1 , b: 2 , c:3 };
var summed = 0;

for (var key in sample) {
    summed += sample[key];
};

http://jsfiddle.net/vZhXs/

jbabey.dll
sumber
1

Saya agak terlambat ke pesta, namun, jika Anda memerlukan solusi yang lebih kuat dan fleksibel, inilah kontribusi saya. Jika Anda hanya ingin menjumlahkan properti tertentu dalam kombo objek / array bersarang, serta melakukan metode agregat lainnya, maka berikut adalah fungsi kecil yang telah saya gunakan pada proyek React:

var aggregateProperty = function(obj, property, aggregate, shallow, depth) {
    //return aggregated value of a specific property within an object (or array of objects..)

    if ((typeof obj !== 'object' && typeof obj !== 'array') || !property) {
        return;
    }

    obj = JSON.parse(JSON.stringify(obj)); //an ugly way of copying the data object instead of pointing to its reference (so the original data remains unaffected)
    const validAggregates = [ 'sum', 'min', 'max', 'count' ];
    aggregate = (validAggregates.indexOf(aggregate.toLowerCase()) !== -1 ? aggregate.toLowerCase() : 'sum'); //default to sum

    //default to false (if true, only searches (n) levels deep ignoring deeply nested data)
    if (shallow === true) {
        shallow = 2;
    } else if (isNaN(shallow) || shallow < 2) {
        shallow = false;
    }

    if (isNaN(depth)) {
        depth = 1; //how far down the rabbit hole have we travelled?
    }

    var value = ((aggregate == 'min' || aggregate == 'max') ? null : 0);
    for (var prop in obj) {
        if (!obj.hasOwnProperty(prop)) {
            continue;
        }

        var propValue = obj[prop];
        var nested = (typeof propValue === 'object' || typeof propValue === 'array');
        if (nested) {
            //the property is an object or an array

            if (prop == property && aggregate == 'count') {
                value++;
            }

            if (shallow === false || depth < shallow) {
                propValue = aggregateProperty(propValue, property, aggregate, shallow, depth+1); //recursively aggregate nested objects and arrays
            } else {
                continue; //skip this property
            }
        }

        //aggregate the properties value based on the selected aggregation method
        if ((prop == property || nested) && propValue) {
            switch(aggregate) {
                case 'sum':
                    if (!isNaN(propValue)) {
                        value += propValue;
                    }
                    break;
                case 'min':
                    if ((propValue < value) || !value) {
                        value = propValue;
                    }
                    break;
                case 'max':
                    if ((propValue > value) || !value) {
                        value = propValue;
                    }
                    break;
                case 'count':
                    if (propValue) {
                        if (nested) {
                            value += propValue;
                        } else {
                            value++;
                        }
                    }
                    break;
            }
        }
    }

    return value;
}

Ini rekursif, non ES6, dan seharusnya berfungsi di sebagian besar browser semi-modern. Anda menggunakannya seperti ini:

const onlineCount = aggregateProperty(this.props.contacts, 'online', 'count');

Rincian parameter:

obj = salah satu objek atau
properti array = properti dalam objek / array bertingkat yang ingin Anda lakukan metode
agregat pada agregat = metode agregat (jumlah, min, maks, atau jumlah)
shallow = dapat disetel ke true / false atau nilai numerik
depth = harus dibiarkan nol atau tidak ditentukan (digunakan untuk melacak callback rekursif berikutnya)

Shallow dapat digunakan untuk meningkatkan kinerja jika Anda tahu bahwa Anda tidak perlu mencari data yang sangat bertingkat. Misalnya jika Anda memiliki array berikut:

[
    {
        id: 1,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    {
        id: 2,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    {
        id: 3,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    ...
]

Jika Anda ingin menghindari perulangan melalui properti otherData karena nilai yang akan Anda gabungkan tidak bertumpuk sedalam itu, Anda dapat menyetel dangkal ke true.


sumber
1

Gunakan Lodash

 import _ from 'Lodash';
 
 var object_array = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}];
 
 return _.sumBy(object_array, 'c')
 
 // return => 9

Ismael Soschinski
sumber
1

let prices = {
  "apple": 100,
  "banana": 300,
  "orange": 250
};

let sum = 0;
for (let price of Object.values(prices)) {
  sum += price;
}

alert(sum)

Sudam Dissanayake
sumber
0

Saya menemukan solusi ini dari @jbabey ketika mencoba memecahkan masalah serupa. Dengan sedikit modifikasi, saya benar. Dalam kasus saya, kunci objek adalah angka (489) dan string ("489"). Karenanya untuk menyelesaikan ini, setiap kunci diurai. Kode berikut berfungsi:

var array = {"nR": 22, "nH": 7, "totB": "2761", "nSR": 16, "htRb": "91981"}
var parskey = 0;
for (var key in array) {
    parskey = parseInt(array[key]);
    sum += parskey;
};
return(sum);
Olu Adabonyan
sumber
0

Sebuah ramda one liner:

import {
 compose, 
 sum,
 values,
} from 'ramda'

export const sumValues = compose(sum, values);

Menggunakan: const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });

Damian Green
sumber
0

Kita dapat melakukan iterasi objek menggunakan kata kunci dalam dan dapat melakukan operasi aritmatika apa pun.

// input
const sample = {
    'a': 1,
    'b': 2,
    'c': 3
};

// var
let sum = 0;

// object iteration
for (key in sample) {
    //sum
    sum += (+sample[key]);
}
// result
console.log("sum:=>", sum);

sachinsuthariya.dll
sumber
0

Jumlahkan nilai kunci objek dengan parse Integer. Mengonversi format string menjadi integer dan menjumlahkan nilainya

var obj = {
  pay: 22
};
obj.pay;
console.log(obj.pay);
var x = parseInt(obj.pay);
console.log(x + 20);

Surya R Praveen
sumber