Bir JavaScript nesnesinin değerleri nasıl toplanır?


87

Bir nesnenin değerlerini toplamak istiyorum.

Ben olduğu yerde python'a alışkınım:

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

Aşağıdaki kod işe yarıyor, ancak çok fazla kod var:

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)

Açıkça bir şey mi kaçırıyorum, yoksa bu böyle mi?

Yanıtlar:


77

Hepsini tek bir işleve koyabilirsiniz:

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


Eğlence uğruna, burada Object.keys()ve kullanan başka bir uygulama Array.reduce()(tarayıcı desteği artık büyük bir sorun olmamalı):

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

Ancak bu çok daha yavaş görünüyor: jsperf.com


Dönüş miktar + parseFloat (obj [anahtar] || 0) Falsey veya null kontrol etmek / boş değerler
sumit

1
Çözümler arasındaki performans farkını vurgulayan harika bir iş. Object.keys().reduceGörünüşü çok daha şık olmakla birlikte ,% 60 daha yavaştır.
micnguyen

104

Bu kadar basit olabilir:

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

MDN'den alıntı yapmak:

Object.values()Yöntem tarafından sağlanan ile aynı sırada, belirli bir nesnenin kendi numaralandırılabilir özellik değerleri bir dizi döner for...in(fark, bir hazır prototip zincirinde döngü sıralar özellikleri de) döngü.

dan Object.values()MDN'yi üzerinde

reduce()Yöntem, tek bir değere düşürmek için bir akümülatör karşı bir işlev (soldan sağa gelen) dizisinin her bir değeri geçerlidir.

dan Array.prototype.reduce()MDN'yi üzerinde

Bu işlevi şu şekilde kullanabilirsiniz:

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

Bu kodun, bazı eski tarayıcılar (IE gibi) tarafından desteklenmeyen bazı ECMAScript özelliklerini kullandığını unutmayın. Kodunuzu derlemek için Babel kullanmanız gerekebilir .


3
Bu, 60K kitaplık çekmenizi gerektirir sadece sahip olmak Object.values()bir ile polyfilled olacak forFirefox yanında her tarayıcıda döngü. Polyfill olmasa bile forbenim için normal bir döngüden 4 kat daha yavaş .
Blender

10
@Blender Yeni ECMAScript özelliklerinden herhangi birini kullanmak ve yine de eski tarayıcıları desteklemek istiyorsanız, yine de Babel kullanmanız gerekir . Ayrıca, birisi bu soruyu örneğin 2 yıl sonra ziyaret ederse, modern tarayıcılar muhtemelen Object.values()o zamana kadar uygulayacaktır .
Michał Perłakowski

Kabul edilen yanıt çok benzer bir yaklaşıma sahip, ancak geçilen işlev reducebiraz daha kusursuz görünüyor. Ayrıştırmayı bilerek mi atladınız?
Cerbrus

@Cerbrus O nesnedeki tüm değerlerin sayı olduğunu varsaydım.
Michał Perłakowski

12
@Blender Görünüşe göre haklıydım - bir buçuk yıl geçti ve Object.values()tüm modern tarayıcılar tarafından destekleniyor .
Michał Perłakowski

25

Lodash kullanıyorsanız aşağıdaki gibi bir şey yapabilirsiniz:

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

20

Düzenli bir fordöngü oldukça kısadır:

var total = 0;

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

object.hasOwnPropertyPrototipi değiştirdiyseniz eklemeniz gerekebilir .


15

Dürüst olmak gerekirse, "modern zamanlarımız" göz önüne alındığında, mümkün olduğunda işlevsel bir programlama yaklaşımını tercih ederim, şöyle:

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

acc0 değeriyle başlayan akümülatörümüz , nesnemizin tüm döngülü değerlerini toplar. Bunun, herhangi bir iç veya dış değişkene bağlı olmama ek faydası vardır; sabit bir işlev olduğundan yanlışlıkla üzerine yazılmaz ... ES2015 için kazanın!


13

Artık reducefonksiyonu kullanabilir ve toplamı alabilirsiniz.

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

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


12

Basit bir for...indöngü kullanmaman için herhangi bir sebep var mı ?

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

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

http://jsfiddle.net/vZhXs/


1

Partiye biraz geç kaldım, ancak daha sağlam ve esnek bir çözüme ihtiyacınız varsa, işte benim katkım. İç içe geçmiş bir nesne / dizi kombinasyonunda yalnızca belirli bir özelliği toplamak ve diğer toplama yöntemlerini gerçekleştirmek istiyorsanız, işte bir React projesinde kullandığım küçük bir işlev:

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

Özyinelemelidir, ES6 değildir ve yarı modern tarayıcıların çoğunda çalışmalıdır. Bunu şu şekilde kullanırsın:

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

Parametre dökümü:

obj = ya bir nesne ya da bir dizi
özelliği = aggregate üzerinde
toplama yöntemini gerçekleştirmek istediğiniz yuvalanmış nesneler / diziler içindeki özellik = toplama yöntemi (sum, min, max veya count)
sığ = ya true olarak ayarlanabilir / false veya sayısal bir değer
derinliği = boş veya tanımsız bırakılmalıdır (sonraki özyinelemeli geri aramaları izlemek için kullanılır)

Derinlemesine iç içe geçmiş verileri aramanız gerekmeyeceğini biliyorsanız, sığ işlevi performansı artırmak için kullanılabilir. Örneğin aşağıdaki diziye sahipseniz:

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

Toplayacağınız değer o kadar derinlemesine iç içe olmadığından otherData özelliğinde döngü yapmaktan kaçınmak istiyorsanız sığ seçeneğini true olarak ayarlayabilirsiniz.


1

Lodash kullanın

 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


1

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

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

alert(sum)


0

Benzer bir sorunu çözmeye çalışırken @jbabey'den bu çözüme rastladım. Küçük bir değişiklikle, doğru anladım. Benim durumumda, nesne anahtarları sayılar (489) ve dizelerdir ("489"). Dolayısıyla bunu çözmek için her anahtar ayrıştırılır. Aşağıdaki kod çalışır:

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

0

Bir ramda tek astar:

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

export const sumValues = compose(sum, values);

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


0

Biz kullanarak nesneyi yineleme yapabilirsiniz içinde anahtar kelime ve herhangi aritmetik işlem gerçekleştirebilir.

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


0

Tamsayı ayrıştırarak nesne anahtar değerini toplayın. Dize biçimini tam sayıya dönüştürme ve değerleri toplama

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

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.