JavaScriptオブジェクトの値を合計する方法は?


86

オブジェクトの値を合計したいのですが。

私はそれがちょうどあるであろうところにPythonに慣れています:

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

次のコードは機能しますが、多くのコードです。

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)

私は明らかな何かを見逃していますか、それともこれはそのままですか?

回答:


74

すべてを1つの関数にまとめることができます。

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


楽しみのために、ここにObject.keys()andを使用した別の実装がありますArray.reduce()(ブラウザのサポートはもう大きな問題ではないはずです):

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

しかし、これははるかに遅いようです:jsperf.com


falsey又はヌル/ブランク値をチェックする戻り和+ parseFloatは(OBJ [キー] || 0)
SUMIT

1
ソリューション間のパフォーマンスの違いを強調する素晴らしい仕事。一方でObject.keys().reduceそんなによりエレガントなルックス、それが60%遅くなります。
micnguyen

101

それはそれと同じくらい簡単かもしれません:

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

MDNの引用:

このObject.values()メソッドは、指定されたオブジェクト自体の列挙可能なプロパティ値の配列を、for...inループによって提供される順序と同じ順序で返します(違いは、for-inループがプロトタイプチェーンのプロパティも列挙することです)。

MDNからObject.values()

このreduce()メソッドは、アキュムレータと配列の各値(左から右へ)に対して関数を適用して、単一の値に減らします。

MDNからArray.prototype.reduce()

この関数は次のように使用できます。

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

このコードは、一部の古いブラウザ(IEなど)ではサポートされていないECMAScript機能を使用していることに注意してください。コードをコンパイルするには、Babelを使用する必要がある場合があります。


3
これは60Kライブラリを引く必要がちょうど持っているObject.values()とpolyfilledされる、forFirefoxのほか、すべてのブラウザでループ。ポリフィルがなくても、通常のforループより4倍遅くなります。
Blender 2016

10
@Blender新しいECMAScript機能のいずれかを使用し古いブラウザを引き続きサポートする場合は、とにかくBabelを使用する必要があります。さらに、たとえば2年後に誰かがこの質問にアクセスした場合、最新のブラウザはおそらくObject.values()その時まで実装されます。
のMichałPerłakowski

受け入れられた回答のアプローチは非常に似ていますが、渡された関数はreduceもう少し確実なようです。わざと構文解析を省略しましたか?
Cerbrus 2016

@Cerbrusそのオブジェクトのすべての値は数値であると想定しました。
のMichałPerłakowski

12
@Blender私は正しかったようです– 1年半が経過し、Object.values()すべての最新のブラウザでサポートされています
のMichałPerłakowski

25

lodashを使用している場合は、次のようなことができます。

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

20

通常のforループはかなり簡潔です。

var total = 0;

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

object.hasOwnPropertyプロトタイプを変更した場合は、追加する必要があるかもしれません。


14

正直なところ、私たちの「現代」を考えると、可能な限り関数型プログラミングのアプローチを採用します。

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

アキュムレータaccは、値0から始まり、オブジェクトのループされたすべての値を累積しています。これには、内部変数または外部変数に依存しないという追加の利点があります。これは定数関数なので、誤って上書きされることはありません... ES2015で勝ちましょう!


12

単純なfor...inループを使用していない理由は何ですか?

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

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

http://jsfiddle.net/vZhXs/


11

これで、reduce関数を利用して合計を取得できます。

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

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


1

私はパーティーに少し遅れていますが、より堅牢で柔軟なソリューションが必要な場合は、ここに私の貢献があります。ネストされたオブジェクト/配列の組み合わせで特定のプロパティのみを合計し、他の集計メソッドを実行する場合は、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;
}

これは再帰的でES6以外であり、ほとんどのセミモダンブラウザで機能するはずです。あなたはそれをこのように使います:

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

パラメータの内訳:

obj =オブジェクトまたは配列のいずれかの
プロパティ=ネストされたオブジェクト/配列内のプロパティで集計メソッドを実行します
aggregate =集計メソッド(合計、最小、最大、またはカウント)
shash = trueに設定できます/ falseまたは数値の
depth = nullまたは未定義のままにする必要があります(後続の再帰的コールバックを追跡するために使用されます)

深くネストされたデータを検索する必要がないことがわかっている場合は、Shallowを使用してパフォーマンスを向上させることができます。たとえば、次の配列がある場合:

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

集計する値がそれほど深くネストされていないため、otherDataプロパティのループを回避したい場合は、shallowをtrueに設定できます。


1

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



0

同様の問題を解決しようとしているときに、@ jbabeyからこの解決策に出くわしました。少し変更を加えるだけで、うまくいきました。私の場合、オブジェクトキーは数字(489)と文字列( "489")です。したがって、これを解決するために、各キーは解析されます。次のコードが機能します。

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

RAMDAの1ライナー:

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

export const sumValues = compose(sum, values);

使用する: const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });


0

inキーワードを使用してオブジェクトを反復処理し任意の算術演算を実行できます。

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

整数を解析してオブジェクトのキー値を合計します。文字列形式を整数に変換し、値を合計する

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.