オブジェクトの値を合計したいと思います。
私は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)
私は明らかなものを見逃していますか、これはそのままですか?
それと同じくらい簡単です:
const sumValues = obj => Object.values(obj).reduce((a, b) => a + b);
MDNの引用:
Object.values()
メソッドは、特定のオブジェクトの列挙可能なプロパティ値の配列を、for...in
ループで提供される順序と同じ順序で返します(違いはfor-inループは、プロトタイプチェーンのプロパティも列挙します)。
reduce()
メソッドは、アキュムレータと配列の各値(左から右へ)に対して関数を適用して、単一の値に減らします。
from Array.prototype.reduce()
on MDN
この機能は次のように使用できます。
sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5
このコードは、一部の古いブラウザ(IEなど)でサポートされていないECMAScript機能を使用していることに注意してください。コードをコンパイルするために Babel を使用する必要がある場合があります。
通常のfor
ループはかなり簡潔です。
var total = 0;
for (var property in object) {
total += object[property];
}
プロトタイプを変更した場合は、object.hasOwnProperty
を追加する必要があります。
Lodashを使用している場合は、次のようなことができます
_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 }))
単純なfor...in
ループを使用しているのではない理由は何ですか?
var sample = { a: 1 , b: 2 , c:3 };
var summed = 0;
for (var key in sample) {
summed += sample[key];
};
正直なところ、「現代」を考えると、可能な限り関数型プログラミングのアプローチを採用します。
const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
0の値で始まるアキュムレーターacc
は、オブジェクトのすべてのループ値を累積しています。これには、内部変数または外部変数に依存しないという利点があります。これは定数関数なので、誤って上書きされることはありません... ES2015で勝ちます!
これで、reduce
関数を使用して合計を取得できます。
const object1 = { 'a': 1 , 'b': 2 , 'c':3 }
console.log(Object.values(object1).reduce((a, b) => a + b, 0));
私はパーティーに少し遅れていますが、より堅牢で柔軟なソリューションが必要な場合は、ここに私の貢献があります。ネストされたオブジェクト/配列コンボの特定のプロパティのみを合計し、他の集計メソッドを実行する場合、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 =集約メソッド(sum、min、max、またはcount)
shallow = true/falseまたは数値に設定できます
depth = nullまたは未定義のままにする必要があります(後続の再帰コールバックを追跡するために使用されます)
深くネストされたデータを検索する必要がないことがわかっている場合、Shallowを使用してパフォーマンスを向上できます。たとえば、次の配列がある場合:
[
{
id: 1,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 2,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 3,
otherData: { ... },
valueToBeTotaled: ?
},
...
]
集約する値がそれほど深くネストされていないため、otherDataプロパティのループを回避したい場合は、shallowをtrueに設定できます。
A ramda 1つのライナー:
import {
compose,
sum,
values,
} from 'ramda'
export const sumValues = compose(sum, values);
使用:const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });
同様の問題を解決しようとして、@ 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);