JavaScriptでオブジェクト配列から重複するidキーを持つ要素を削除する方法
例えば、次のようなURLとidを持つオブジェクトの配列があるとします。
const arr = [
{
url: 'www.example.com/hello',
id: "22"
},
{
url: 'www.example.com/hello',
id: "22"
},
{
url: 'www.example.com/hello-how-are-you',
id: "23"
},
{
url: 'www.example.com/i-like-cats',
id: "24"
},
{
url: 'www.example.com/i-like-pie',
id: "25"
}
];
この中には、同じid("22")を持つオブジェクトが2つ含まれています。今回の課題は、このような配列を受け取り、重複したidキーを持つオブジェクトを配列から取り除くJavaScript関数を作成することです。ただし、underscoreなどの外部ライブラリは使用せず、素のJavaScriptだけで実装することが条件です。
実装例:splice()を使った方法
まずは、元の配列から直接重複を取り除くシンプルな実装を見てみましょう。
const arr = [
{
url: 'www.example.com/hello',
id: "22"
},
{
url: 'www.example.com/hello',
id: "22"
},
{
url: 'www.example.com/hello-how-are-you',
id: "23"
},
{
url: 'www.example.com/i-like-cats',
id: "24"
},
{
url: 'www.example.com/i-like-pie',
id: "25"
}
];
const removeDuplicate = (arr = []) => {
const map = {};
for(let i = 0; i < arr.length; ){
const { id } = arr[i];
if(map.hasOwnProperty(id)){
arr.splice(i, 1);
}else{
map[id] = true;
i++;
}
}
};
removeDuplicate(arr);
console.log(arr);
コードの動作解説
この関数のロジックを順番に確認していきます。
- 最初に空のオブジェクト
mapを用意し、「すでに登場したid」の記録簿として利用します。 forループで配列を先頭から走査します。重要なのは、要素を削除したときだけループカウンタiを増やさない点です。splice()で要素を1つ削除すると、後続の要素が自動的に前に詰められるため、iを固定したままにすることで次の要素を見逃しません。const { id } = arr[i];という分割代入で現在のオブジェクトからidを取り出し、hasOwnProperty()によって登録済みかどうかを判定します。- 未登録の場合は
map[id] = true;で記録してからi++で次へ進み、登録済みの場合はarr.splice(i, 1)で該当オブジェクトを削除します。
この処理により、各idについて最初に出現したオブジェクトだけが残り、2回目以降の出現分がすべて削除されます。
出力結果
コンソールには次のように表示されます。
[
{ url: 'www.example.com/hello', id: '22' },
{ url: 'www.example.com/hello-how-are-you', id: '23' },
{ url: 'www.example.com/i-like-cats', id: '24' },
{ url: 'www.example.com/i-like-pie', id: '25' }
]
別解:filter()とSetを組み合わせるモダンな書き方
上記の方法は元の配列を直接書き換える(破壊的な)アプローチです。一方、元の配列を保持したまま新しい配列として重複除去の結果を得たい場合は、filter()とSetを組み合わせるのがおすすめです。
const removeDuplicate = (arr = []) => {
const seen = new Set();
return arr.filter(obj => {
if(seen.has(obj.id)){
return false;
}
seen.add(obj.id);
return true;
});
};
const uniqueArr = removeDuplicate(arr);
console.log(uniqueArr);
filter()は、コールバックがtrueを返した要素だけを集めた新しい配列を返します。また、Setによる一意性判定は非常に高速なため、要素数の多い配列でも効率的に動作します。Reactなどで状態管理を行う場合や、元データを壊したくない場面では、このイミュータブルな手法が特に役立ちます。
まとめ
- 重複判定の基準となるプロパティ(ここでは
id)を決め、出現済みかどうかを記録しながら走査するのが基本戦略です。 - 元の配列を書き換えてよいなら
splice()方式、新しい配列が必要ならfilter()+Set方式を選びましょう。 - どちらの方法も外部ライブラリ不要で、数行のコードで簡単に実装できます。
-
JavaScriptで配列からfalsyな値を削除する方法【_.compact()の使い方】
JavaScriptのライブラリ underscore.js には、配列からすべてのfalsyな値を取り除くための _.compact() メソッドが用意されています。ここでいうfalsyな値とは、NaN、undefined、空文字列()、false、0 のことです。このメソッドは、falsyな値がすべて除去された新しい配列を返します。元の配列は変更されないため、安全に利用できます。 構文 _.compact( array ); 引数として配列を1つ受け取り、falsyな値が取り除かれた新しい配列を戻り値として返します。 使用例 次の例では、配列に含まれる NaN、false、空文字列、und
-
JavaScriptのArray.values()メソッドとは?使い方とサンプルコードを徹底解説
JavaScriptのArray.values()メソッドとは? JavaScriptのArray.values()メソッドは、対象の配列に含まれるすべての値を格納したイテレーターオブジェクトを返します。ES2015(ES6)以降で利用可能なこのメソッドは、for...ofループやスプレッド構文([...arr])と組み合わせることで、配列の各要素を効率的に取り出せます。 なお、keys()やentries()がインデックス情報も一緒に返すのに対し、values()は純粋に「値」だけを順番に提供する点が大きな特徴です。 基本構文 arr.values() 引数は不要で、戻り値として新しいArr