Array.prototype.reduce 単体
要件を達成する方法としてはおそらく最速。
(Array.prototype.reduce
を使わなければもっと速いですが、reduce を使う条件なのでそこは置いておきます。)
JavaScript
1'use strict';
2var src = [{'name':'abc','value':100},{'name':'def','value':50},{'name':'abc','value':123},{'name':'hij','value':789},{'name':'def','value':1}];
3
4var results = src.reduce(function (results, current) {
5 for (var i = 0, l = results.length, name = current.name, object; i < l; ++i) {
6 object = results[i];
7
8 if (object.name === name) {
9 object.value += current.value;
10 return results;
11 }
12 }
13
14 results.push(current);
15
16 return results;
17}, []);
18
19console.log(JSON.stringify(results)); // [{"name":"abc","value":223},{"name":"def","value":51},{"name":"hij","value":789}]
オブジェクト初期化子
このコードは name
が String
型であることが確定している必要があります。
JavaScript
1'use strict';
2var src = [{'name':'abc','value':100},{'name':'def','value':50},{'name':'abc','value':123},{'name':'hij','value':789},{'name':'def','value':1}];
3
4var object = src.reduce(function (object, current) {
5 var name = current.name;
6
7 if (object.hasOwnProperty(name)) {
8 object[name] += current.value;
9 } else {
10 object[name] = current.value;
11 }
12
13 return object;
14}, {});
15
16var results = Object.keys(object).map(function (key) {
17 return {name: key, value: object[key]};
18});
19
20console.log(JSON.stringify(results)); // [{"name":"abc","value":223},{"name":"def","value":51},{"name":"hij","value":789}]
オブジェクト初期化子 + Object.entries (ES8)
先行仕様(ES8/ES2017)ですが、Object.entries
を利用するとオブジェクト初期化子のコードを更にエレガントに書けます。
Object.entries
は Polyfill コードがあるので、現行でも使おうと思えば使えます。
JavaScript
1'use strict';
2var src = [{'name':'abc','value':100},{'name':'def','value':50},{'name':'abc','value':123},{'name':'hij','value':789},{'name':'def','value':1}];
3
4var results = Object.entries(src.reduce((object, current) => {
5 var name = current.name;
6
7 if (object.hasOwnProperty(name)) {
8 object[name] += current.value;
9 } else {
10 object[name] = current.value;
11 }
12
13 return object;
14}, {})).map(entry=>{
15 return {name: entry[0], value: entry[1]};
16});
17
18console.log(JSON.stringify(results)); // [[{"name":"abc","value":223},{"name":"def","value":51},{"name":"hij","value":789}]
new Map (ES6)
オブジェクト初期化子で「name
が String
型でなければならない」欠点を new Map
で克服しており、可搬性が最も高いと思われます。
構造を変えていいのなら、Map.prototype.entries
の出力値で十分かもしれません。
JavaScript
1'use strict';
2var src = [{'name':'abc','value':100},{'name':'def','value':50},{'name':'abc','value':123},{'name':'hij','value':789},{'name':'def','value':1}],
3 map = new Map,
4 results = [];
5
6src.reduce(function (map, current) {
7 var name = current.name;
8
9 map.set(name, map.has(name) ? map.get(name) + current.value : current.value);
10
11 return map;
12}, map).forEach(function (value, key, map) {
13 this.push({name: key, value: value});
14}, results);
15
16console.log(JSON.stringify(results)); // [[{"name":"abc","value":223},{"name":"def","value":51},{"name":"hij","value":789}]
17console.log(JSON.stringify([...map.entries()])); // [["abc",223],["def",51],["hij",789]]
更新履歴
- 2016/12/28 00:08 new Mapコードを Object.keys -> Map#forEach
- 2016/12/28 00:32 new Mapコードを三項演算子を使ったコードに修正
- 2016/12/28 01:38 オブジェクト初期化子 + Object.entriesのコード追記
Re: stakezaki さん