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を駆使して簡単にできました。