前提・実現したいこと
オブジェクトの配列を、キーの値が同じオブジェクトの配列の配列としてまとめるにはどうしたら良いか悩んでいます。
具体的には、コード内にあるarray_1の配列から、array_3の様な構造の配列を新規に作成したいです。
キーnameの値が同じオブジェクトをまとめて配列を作成するまではできたのですが、(array_1からarray_2の状態)
キーidの値が同じものでさらにまとめたい場合(array_2からarray_3の状態)の処理で良い方法が思いつきません。
array_1の配列から、array_3の様な構造にする為に処理を2回に分けているのですが、
他にも良いやり方があればご教示願いたいです。
javascript
1var array_1 = [ 2 { id: 0, name: "a"}, 3 { id: 2, name: "b"}, 4 { id: 3, name: "b"}, 5 { id: 3, name: "b"} 6] 7var array_2 = [ 8 [ 9 { id: 0, name: "a"} 10 ], 11 [ 12 { id: 2, name: "b"}, 13 { id: 3, name: "b"}, 14 { id: 3, name: "b"} 15 ] 16] 17var array_3 = [ 18 [ 19 { id: 0, name: "a"} 20 ], 21 [ 22 { id: 2, name: "b"} 23 ], 24 [ 25 { id: 3, name: "b"}, 26 { id: 3, name: "b"} 27 ] 28]
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/07/13 03:59
回答4件
0
こんにちは。
array_2 を経由せずに、array_1 から直接array_3を得る方法として、
以下を考えました。
javascript
1var array_3 = array_1.reduce(function(a, e) { 2 a.some(x => x[0].id == e.id && x[0].name == e.name && x.push(e)) || a.push([e]); 3 return a; 4}, []);
以下にて、動作確認しています。
https://jsfiddle.net/jun68ykt/Lfy3odqu/42/
参考になれば幸いです。
補足
上記のコード中、以下の行
a.some(x => x[0].id == e.id && x[0].name == e.name && x.push(e)) || a.push([e]);
について、以下の2点を補足します。
(1) x.push(e)
は、e
が追加された後のx
の長さを返すので、x.push(e)
の返す値は常に1以上の整数であり、1以上の整数を論理値として評価すると true
になります。これを some メソッドから true
を返させるために使っています。
(2) x[0]
とe
との比較で、プロパティ id
、name
ともに等しいかを検証する前に、念のため先頭に x
が空の配列ではない検証を追加して、
x.length > 0 && x[0].id == e.id && ・・・
としなくてもよい 理由は、a
に要素が追加されるのは、
a.push([e])
のときしかないので、a
の要素である配列 x
は空ではなく、
少なくとも1個の要素を持つことが分かっているからです。
投稿2018/07/12 21:20
編集2018/07/13 01:35総合スコア9058
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/07/13 04:16
2018/07/13 04:32
2018/07/13 05:20
0
ベストアンサー
2次元配列にした時点でかなり触りづらいですね。
なので質問文のケースではarray_1から2を経由するのではなく、
直接array_3に加工した方が早いです。
Object.values()を使えば一発解決するんじゃないですかね?
JavaScript
1var array_1 = [ 2 { id: 0, name: "a"}, 3 { id: 2, name: "b"}, 4 { id: 3, name: "b"}, 5 { id: 3, name: "b"} 6] 7var tmp = {}; // 空のオブジェクトを宣言しておく 8for (var it of array_1) { 9 var key = `${it.id}-${it.name}`; 10 if (tmp[key]) { 11 tmp[key].push(it); 12 } else { 13 tmp[key] = [it]; 14 } 15} 16 17console.log(tmp); 18console.log(Object.values(tmp)); 19// この中身は実際に動作して確認してみてね
投稿2018/07/12 14:34
総合スコア21158
0
すでに回答いただいておりますが、
自分でもなんとか下記の様に解決することができました。
比べるとすごい冗長、、、
javascript
1var array_1 = [ 2 { id: 0, name: "a"}, 3 { id: 2, name: "b"}, 4 { id: 3, name: "b"}, 5 { id: 3, name: "b"} 6] 7console.log("array_1", array_1); 8 9var key = "name" 10var array_2 = []; 11 12array_2 = getMargeArr(array_1, "name"); 13console.log("array_2", array_2); 14 15var array_3 = []; 16 17for (var i in array_2) { 18 var subArr = []; 19 subArr = getMargeArr(array_2[i], "id"); 20 Array.prototype.push.apply(array_3, subArr); 21} 22console.log(array_3); 23 24 25function getMargeArr(arr, key){ 26 var newArr = []; 27 for (var i in arr) { 28 if(typeof arr[i][key] !== undefined){ 29 var target_val = arr[i][key]; 30 var searchArr = searchArray(newArr, target_val, key) 31 32 if (searchArr === undefined) { 33 searchArr = [] 34 newArr.push(searchArr) 35 } 36 searchArr.push(arr[i]) 37 } 38 } 39 return newArr 40} 41 42function searchArray(list, target_val, key) { 43 if(list.length !== 0){ 44 for (var i in list) { 45 if (list[i][0][key] === target_val) { 46 return list[i] 47 } 48 } 49 } 50 return undefined 51}
投稿2018/07/13 03:58
総合スコア13
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
問題点
JavaScript
1var array_3 = [ 2 [ 3 { id: 0, name: "a"} 4 ], 5 [ 6 { id: 2, name: "b"} 7 ], 8 [ 9 { id: 3, name: "b"}, 10 { id: 3, name: "b"} 11 ] 12]
期待する配列に問題があるように感じます。
(問題1) 特定の id
を持つオブジェクト群を探す為に全要素を検索しなければならない
(問題2) id
の若い順番でソートすることまで期待しているのか不明
(問題1) については要求仕様の問題でせっかくid別に分類したのに、特定idを探し出す為に余計なコストがかかってしまいます。
(問題2) については既存の全回答で No ですが、array_1
が若番順でソートされているので、質問者がその問題に気が付いてない懸念があります。
new Map (定義順)
(問題1) は new Map
で解決できます。
ただし、Map は定義順で iterable なオブジェクトを生成するので、愚直に set すると id の若番順で並びません。
JavaScript
1'use strict'; 2function toMap (array) { 3 return array.reduce(function (map, current) { 4 var id = current.id; 5 6 delete current.id; 7 map.has(id) ? map.get(id).push(current) : map.set(id, [current]); 8 9 return map; 10 }, new Map); 11} 12 13var array_1 = [{id: 0, name: "a"}, {id: 2, name: "b"}, { id: 3, name: "b"}, {id: 3, name: "b"}], 14 array_2 = [{id: 3, name: "b"}, {id: 3, name: "b"}, {id: 2, name: "b"}, {id: 0, name: "b"}]; 15 16 17console.log(JSON.stringify([...toMap(array_1)])); // [[0,[{"name":"a"}]],[2,[{"name":"b"}]],[3,[{"name":"b"},{"name":"b"}]]] 18console.log(JSON.stringify([...toMap(array_2)])); // [[3,[{"name":"b"},{"name":"b"}]],[2,[{"name":"b"}]],[0,[{"name":"b"}]]]
配列 (若番順)
(問題2) への対策として、配列で解決する方法があります。
配列は定義順ではなく、若番順で列挙する事が期待できます。
ただし、id が配列のプロパティ名に依存するので、id を String 型に変換してしまいます。
id
の型を維持するのであれば、new Map
が妥当です。
JavaScript
1'use strict'; 2function toArray (array) { 3 return array.reduce(function (array, current) { 4 var id = current.id; 5 6 delete current.id; 7 id in array ? array[id].push(current) : array[id] = [current]; 8 9 return array; 10 }, []); 11} 12 13var array_1 = [{id: 0, name: "a"}, {id: 2, name: "b"}, { id: 3, name: "b"}, {id: 3, name: "b"}], 14 array_2 = [{id: 3, name: "b"}, {id: 3, name: "b"}, {id: 2, name: "b"}, {id: 0, name: "b"}]; 15 16console.log(toArray(array_1)); // [[{"name":"a"}],,[{"name":"b"}],[{"name":"b"},{"name":"b"}]] 17console.log(toArray(array_2)); // [[{"name":"a"}],,[{"name":"b"}],[{"name":"b"},{"name":"b"}]]
new Map (若番順)
new Map
を呼び出す前にソートすれば、id の若番順で並びます。
JavaScript
1function toMap (array) { 2 return new Map(array.reduce(function (array, current) { 3 const id = current.id; 4 5 delete current.id; 6 7 for (let element of array) { 8 if (element[0] === id) { 9 element[1].push(current); 10 return array; 11 } 12 } 13 14 array.push([id, [current]]); 15 return array; 16 }, []).sort(function (a, b) { 17 return a > b; 18 })); 19} 20 21var array_1 = [{id: 0, name: "a"}, {id: 2, name: "b"}, { id: 3, name: "b"}, {id: 3, name: "b"}], 22 array_2 = [{id: 3, name: "b"}, {id: 3, name: "b"}, {id: 2, name: "b"}, {id: 0, name: "b"}]; 23 24console.log(JSON.stringify([...toMap(array_1)])); // [[0,[{"name":"a"}],[2,[{"name":"b"}]],[3,[{"name":"b"},{"name":"b"}]]] 25console.log(JSON.stringify([...toMap(array_2)])); // [[0,[{"name":"a"}]],[2,[{"name":"b"}]],[3,[{"name":"b"},{"name":"b"}]]]
Re: nabanaba さん
投稿2018/07/14 09:01
総合スコア18166
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/07/17 03:00 編集
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。