「オブジェクトのキー」を使ってユニークにする発想
Object.values(_.keyBy(arr, 'id')) は、「オブジェクト配列から、特定のキー(ここでは id)を基準に重複を取り除く」ためのテクニックです。 単なる数値配列なら new Set で重複除去できますが、オブジェクト配列になると「どのプロパティを基準にユニークにするか」を決める必要があります。 そのときに使えるのが、lodash の _.keyBy と Object.values の組み合わせです。
lodash の keyBy がやっていること
_.keyBy(arr, 'id') は、「配列の各要素を、指定したキーを使ってオブジェクトに並べ替える」関数です。
例を見てみます。
const arr = [
{ id: 1, name: "Aki" },
{ id: 2, name: "Mika" },
{ id: 1, name: "Aki (duplicate)" }
];
const keyed = _.keyBy(arr, 'id');
console.log(keyed);
/*
{
1: { id: 1, name: "Aki (duplicate)" },
2: { id: 2, name: "Mika" }
}
*/
JavaScriptここで重要なのは、同じ id のものは、最後に出てきたものが上書きされるという点です。 keyBy は「id をキーにしたオブジェクト」を作るので、 同じキーが複数あれば、最終的にそのキーにはひとつのオブジェクトしか残りません。
つまり、keyBy の時点で 「id ごとに1件だけ」という状態が作られます。 これが「ユニーク化」の核になります。
Object.values で「オブジェクトをまた配列に戻す」
keyBy の結果は「オブジェクト」です。 しかし、最終的に欲しいのは「ユニークなオブジェクトの配列」ですよね。
そこで使うのが Object.values(...) です。
const uniqueArr = Object.values(_.keyBy(arr, 'id'));
console.log(uniqueArr);
/*
[
{ id: 1, name: "Aki (duplicate)" },
{ id: 2, name: "Mika" }
]
*/
JavaScriptObject.values(obj) は、オブジェクトの「値」だけを配列として取り出す関数です。 keyBy で「id ごとに1件だけ」にしたあと、 その「1件ずつ」を配列として取り出すことで、「id を基準にユニークな配列」が完成します。
例題:ユーザー一覧を id でユニークにする
実務でよくあるパターンをイメージしましょう。
const users = [
{ id: 1, name: "Aki" },
{ id: 2, name: "Mika" },
{ id: 1, name: "Aki (from another source)" },
{ id: 3, name: "Ken" }
];
const uniqueUsers = Object.values(_.keyBy(users, 'id'));
console.log(uniqueUsers);
/*
[
{ id: 1, name: "Aki (from another source)" },
{ id: 2, name: "Mika" },
{ id: 3, name: "Ken" }
]
*/
JavaScriptここで起きていることはこうです。 同じ id を持つユーザーが複数いても、最終的に id: 1 のユーザーはひとりだけになります。 どれが残るかというと、「最後に現れたもの」です。
この「最後のものが勝つ」という挙動は、 「後から取得したデータで上書きしたい」ときに都合が良いことが多いです。
「どのキーでユニークにするか」を自分で選べる強さ
_.keyBy(arr, 'id') の 'id' の部分は、もちろん他のプロパティにも変えられます。
メールアドレスでユニークにしたければ 'email'。 商品コードでユニークにしたければ 'code'。
つまり、「この配列は、このプロパティを基準にユニークにしたい」という意図を、そのままコードに表現できるわけです。 これは Set ではできない、オブジェクト配列ならではのユニーク化の考え方です。
まとめ:Object.values(_.keyBy(arr, 'id')) は「オブジェクト配列をキーでユニークにする定番パターン」
数値や文字列の重複なら new Set で十分ですが、 オブジェクト配列になると「どのプロパティを基準にユニークにするか」を決める必要があります。
その答えのひとつが、 Object.values(_.keyBy(arr, 'id')) という書き方です。
keyBy で「キーごとに1件だけ」にまとめる。 Object.values で「その1件ずつを配列として取り出す」。
この流れを理解できると、 「オブジェクト配列の重複除去」という、ひとつ上のレベルの配列処理が自然に書けるようになります。
