JavaScript, TypeScriptで"オブジェクトの配列"を"簡単に"ユニークにしたい。
こちら↓
const arr = [
{ id:"a0", propA: "A0-propA", propB: "A0-propB", ... },
{ id:"a1", propA: "A1-propA", propB: "A1-propB", ... },
{ id:"b0", propA: "B0-propA", propB: "B0-propB", ... },
{ id:"a0", propA: "A0-propA", propB: "A0@propB", ... },
...
];
// シンプルに要素をユニークにする
const uniq_arr_1 = [... arr.reduce((map, a) => map.set(a.id, a), new Map()).values()];
// 要素をユニークにし、変換もする
const uniq_arr_2 = [... arr.reduce((map, a) => map.set(a.id, { id: a.id, value : a.propA, desc: a.propB}), new Map()).values()];
解説
JSやTSで Object Array を distinct したい。オブジェクトの配列要素を特定のプロパティ、メンバで一意にしたい。。。単にArrayをUniqueにする方法でサクッと調べてみるとSet
を使う方法が出てきますが、Set
では要素の等価性、同一性の評価がカスタマイズできないので文字列や数値のような"プリミティブ"な要素の配列にしか使えません。。forやforeachで頑張ればできるのですが、できるだけ"簡単に"やりたい、というわけです。
というわけで、Array.reduce
とMap
を使って、Map
のキーに特定のメンバーを指定することで、配列の要素を一意にし、その後 Map.values()
とスプレッド構文でArray
に戻しております。
ミソはArray.reduce
の第2引数で初期値にnew Map()
を渡すこと、そしてMap.set
で要素を追加している箇所、そしてMap.values
です。
Map.set
は戻り値がMap
なので、Map.set
しただけでそのまま暗黙のreturn map
が出来ております。
また、Map.values()
とスプレッド構文で簡単にArrayに戻すことが出来ています。
というわけでなかなか悩ましいObject Arrayを一意にする方法ですが、Array.reduce
とMap
を駆使して簡単にできました。