読み込み中...

JavaScriptにおける重複チェックの手法8選

JavaScriptの重複チェックを完全に理解 JS
この記事は約22分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●JavaScriptにおける重複チェックとは?

JavaScriptを使ったウェブ開発において、配列やオブジェクトの重複チェックは非常に重要な技術の1つです。

重複したデータを処理することは、アプリケーションのパフォーマンスを低下させ、予期せぬバグを引き起こす可能性があります。

そのため、エンジニアは効果的な重複チェックの手法を身につける必要があります。

○重複チェックの必要性

重複チェックが必要な理由は、大きく分けて2つあります。

1つ目は、データの整合性を保つためです。

例えば、ユーザー登録システムで、同じメールアドレスで複数のアカウントを作成できてしまうと、データの重複が発生し、システムの正確性が損なわれます。

重複チェックを行うことで、このような問題を防ぐことができます。

2つ目は、パフォーマンスの向上です。

重複したデータを処理することは、無駄な計算リソースを消費します。

特に、大量のデータを扱う場合、重複チェックを行わないと、処理時間が著しく長くなってしまいます。

重複を排除することで、アプリケーションの実行速度を改善できます。

○配列とオブジェクトの違い

重複チェックを行う前に、配列とオブジェクトの違いを理解しておく必要があります。

配列は、複数の値を順序付きで格納するためのデータ構造です。

配列内の各要素には、0から始まるインデックス番号が割り当てられます。

配列の重複チェックでは、主に値の比較が行われます。

一方、オブジェクトは、キーと値のペアを格納するためのデータ構造です。

オブジェクトのキーは一意である必要があります。

オブジェクトの重複チェックでは、キーの比較が行われます。

配列とオブジェクトでは、重複チェックの方法が異なります。

配列の場合は、indexOf()やincludes()などのメソッドを使って、値の存在を確認します。

オブジェクトの場合は、hasOwnProperty()メソッドを使って、キーの存在を確認します。

●配列の重複チェック7選

JavaScriptで配列内の重複要素をチェックする方法は、いくつかあります。

ここでは、実務でよく使われる7つの手法を紹介します。

それぞれの手法には長所と短所がありますが、状況に応じて適切な方法を選択することが重要です。

初心者の方でも、これらの手法を理解し、実践することで、配列の重複チェックに自信を持って取り組めるようになるでしょう。

では、早速、1つ目の手法から見ていきましょう。

○手法1:Setを使う方法

Setを使う方法は、ES6で導入されたSet オブジェクトを利用して、配列内の重複要素を削除する方法です。

Setは、ユニークな値のコレクションを表すオブジェクトで、重複する値を自動的に排除してくれます。

Setを使った重複削除の手順は、次の通りです。

  1. 配列をSetオブジェクトに変換する
  2. Setオブジェクトを配列に変換する

この手順を実行することで、重複のない配列を得ることができます。

□サンプルコード1:Setによる重複削除

function removeDuplicates(array) {
  return [...new Set(array)];
}

// 使用例
const originalArray = [1, 2, 3, 2, 4, 1, 5];
const uniqueArray = removeDuplicates(originalArray);
console.log(uniqueArray);

実行結果

[1, 2, 3, 4, 5]

このサンプルコードでは、removeDuplicates()関数内で、まず配列をSetオブジェクトに変換しています。

Setコンストラクタに配列を渡すことで、重複が自動的に削除されます。

次に、スプレッド構文(…)を使って、Setオブジェクトを新しい配列に変換しています。

Setを使う方法は、シンプルで簡潔なコードで実装できる上に、パフォーマンスも優れています。

大規模な配列に対しても効率的に重複削除を行うことができます。

ただし、Setは参照型のオブジェクトや配列を区別できないため、そのようなケースでは別の方法を検討する必要があります。

○手法2:filterを使う方法

filterを使う方法は、配列のfilterメソッドを利用して、重複のない要素だけを新しい配列に追加する方法です。

filterメソッドは、与えられた関数の条件に合致する要素だけを集めた新しい配列を返します。

filterを使った重複チェックの手順は、次の通りです。

  1. 新しい配列を用意する
  2. 元の配列の要素を1つずつチェックする
  3. チェックする要素が新しい配列内に存在しない場合、その要素を新しい配列に追加する

この手順を実行することで、重複のない配列を得ることができます。

□サンプルコード2:filterによる重複チェック

function removeDuplicates(array) {
  return array.filter((element, index, self) => self.indexOf(element) === index);
}

// 使用例
const originalArray = [1, 2, 3, 2, 4, 1, 5];
const uniqueArray = removeDuplicates(originalArray);
console.log(uniqueArray);

実行結果

[1, 2, 3, 4, 5]

このサンプルコードでは、removeDuplicates()関数内で、filterメソッドを使用しています。

filterメソッドのコールバック関数には、3つの引数(element、index、self)が渡されます。

elementは現在処理中の要素、indexはその要素のインデックス、selfは元の配列を表します。

コールバック関数内で、indexOf()メソッドを使って、現在の要素が配列内で最初に出現するインデックスと、現在のインデックスを比較します。

これらが一致する場合、その要素は重複していないと判断され、新しい配列に追加されます。

filterを使う方法は、比較的シンプルで理解しやすい方法です。

ただし、大規模な配列に対して使用する場合、パフォーマンスが悪化する可能性があります。

配列のサイズが大きい場合は、他の方法を検討することをお勧めします。

○手法3:includesを使う方法

includesを使う方法は、配列のincludesメソッドを利用して、重複のない要素だけを新しい配列に追加する方法です。

includesメソッドは、配列内に特定の要素が存在するかどうかを判断します。

includesを使った重複チェックの手順は、次の通りです。

  1. 新しい配列を用意する
  2. 元の配列の要素を1つずつチェックする
  3. チェックする要素が新しい配列内に存在しない場合、その要素を新しい配列に追加する

この手順を実行することで、重複のない配列を得ることができます。

□サンプルコード3:includesによる重複チェック

function removeDuplicates(array) {
  const uniqueArray = [];

  array.forEach((element) => {
    if (!uniqueArray.includes(element)) {
      uniqueArray.push(element);
    }
  });

  return uniqueArray;
}

// 使用例
const originalArray = [1, 2, 3, 2, 4, 1, 5];
const uniqueArray = removeDuplicates(originalArray);
console.log(uniqueArray);

実行結果

[1, 2, 3, 4, 5]

このサンプルコードでは、removeDuplicates()関数内で、新しい配列uniqueArrayを用意しています。

元の配列の要素を1つずつforEachメソッドで処理し、現在の要素がuniqueArray内に存在しない場合(includes()メソッドがfalseを返す場合)、その要素をuniqueArrayに追加します。

includesを使う方法は、シンプルで直感的に理解しやすい方法です。

ただし、大規模な配列に対して使用する場合、パフォーマンスが悪化する可能性があります。

配列のサイズが大きい場合は、他の方法を検討することをお勧めします。

○手法4:indexOfを使う方法

JavaScriptの配列で重複をチェックするもう1つの方法は、indexOfメソッドを使うことです。

indexOfメソッドは、配列内で指定された要素が最初に出現するインデックスを返します。

この方法は、配列内に重複する要素があるかどうかを判断するのに便利です。

では、具体的にindexOfを使った重複チェックの方法を見ていきましょう。

まず、新しい配列を用意し、元の配列の要素を1つずつチェックします。

チェックする要素が新しい配列内にすでに存在する場合(indexOfの戻り値が-1でない場合)、その要素は重複しているとみなされます。

重複していない要素だけを新しい配列に追加することで、重複のない配列を作成できます。

□サンプルコード4:indexOfによる重複チェック

function removeDuplicates(array) {
  const uniqueArray = [];

  for (let i = 0; i < array.length; i++) {
    if (uniqueArray.indexOf(array[i]) === -1) {
      uniqueArray.push(array[i]);
    }
  }

  return uniqueArray;
}

// 使用例
const originalArray = [1, 2, 3, 2, 4, 1, 5];
const uniqueArray = removeDuplicates(originalArray);
console.log(uniqueArray);

実行結果

[1, 2, 3, 4, 5]

このサンプルコードでは、removeDuplicates関数内で新しい配列uniqueArrayを作成しています。

元の配列originalArrayの要素を1つずつチェックし、uniqueArray内にその要素が存在しない場合(indexOfの戻り値が-1の場合)、その要素をuniqueArrayに追加します。

これにより、重複のない配列が作成されます。

indexOfを使った重複チェックは、シンプルで理解しやすい方法です。

ただし、大規模な配列に対して使用する場合、パフォーマンスが悪化する可能性があります。

配列のサイズが大きい場合は、他の方法を検討することをお勧めします。

○手法5:findIndexを使う方法

findIndexメソッドを使って、配列内の重複を検出することもできます。

findIndexは、指定された条件を満たす最初の要素のインデックスを返します。条件を満たす要素がない場合は-1を返します。

findIndexを使った重複チェックでは、新しい配列を作成し、元の配列の要素を1つずつチェックします。

チェックする要素が新しい配列内に存在する場合(findIndexの戻り値が-1でない場合)、その要素は重複しているとみなされます。

重複していない要素だけを新しい配列に追加することで、重複のない配列を作成できます。

□サンプルコード5:findIndexによる重複チェック

function removeDuplicates(array) {
  const uniqueArray = [];

  array.forEach((element) => {
    if (uniqueArray.findIndex((item) => item === element) === -1) {
      uniqueArray.push(element);
    }
  });

  return uniqueArray;
}

// 使用例
const originalArray = [1, 2, 3, 2, 4, 1, 5];
const uniqueArray = removeDuplicates(originalArray);
console.log(uniqueArray);

実行結果

[1, 2, 3, 4, 5]

このサンプルコードでは、removeDuplicates関数内で新しい配列uniqueArrayを作成しています。

元の配列originalArrayの要素を1つずつチェックし、uniqueArray内にその要素が存在しない場合(findIndexの戻り値が-1の場合)、その要素をuniqueArrayに追加します。

これにより、重複のない配列が作成されます。

findIndexを使った重複チェックは、indexOfと同様にシンプルで理解しやすい方法です。

ただし、大規模な配列に対して使用する場合、パフォーマンスが悪化する可能性があります。

配列のサイズが大きい場合は、他の方法を検討することをお勧めします。

○手法6:reduceを使う方法

reduceメソッドを使って、配列内の重複を削除することができます。

reduceは、配列の各要素に対して指定されたコールバック関数を実行し、単一の値を返します。

このコールバック関数内で、重複をチェックし、重複のない要素だけを新しい配列に追加します。

reduceを使った重複チェックでは、コールバック関数の第1引数(accumulator)に新しい配列を渡します。

第2引数(currentValue)には、現在処理中の要素が渡されます。

コールバック関数内で、現在の要素がaccumulator内に存在しない場合、その要素をaccumulatorに追加します。

最終的に、accumulatorが重複のない配列となります。

□サンプルコード6:reduceによる重複チェック

function removeDuplicates(array) {
  return array.reduce((accumulator, currentValue) => {
    if (accumulator.indexOf(currentValue) === -1) {
      accumulator.push(currentValue);
    }
    return accumulator;
  }, []);
}

// 使用例
const originalArray = [1, 2, 3, 2, 4, 1, 5];
const uniqueArray = removeDuplicates(originalArray);
console.log(uniqueArray);

実行結果

[1, 2, 3, 4, 5]

このサンプルコードでは、removeDuplicates関数内でreduceメソッドを使用しています。

コールバック関数の第1引数(accumulator)は、新しい配列として初期化されます。

第2引数(currentValue)には、現在処理中の要素が渡されます。

コールバック関数内で、現在の要素がaccumulator内に存在しない場合(indexOfの戻り値が-1の場合)、その要素をaccumulatorに追加します。

最終的に、accumulatorが重複のない配列となります。

reduceを使った重複チェックは、シンプルで簡潔なコードで実装できます。

ただし、大規模な配列に対して使用する場合、パフォーマンスが悪化する可能性があります。

配列のサイズが大きい場合は、他の方法を検討することをお勧めします。

○手法7:mapを使う方法

mapメソッドを使って、配列内の重複を検出することもできます。

mapは、配列の各要素に対して指定されたコールバック関数を実行し、新しい配列を返します。

このコールバック関数内で、重複をチェックし、重複のない要素だけを新しい配列に追加します。

mapを使った重複チェックでは、新しいMapオブジェクトを作成し、元の配列の要素を1つずつチェックします。

Mapオブジェクトのhasメソッドを使って、現在の要素がすでにMap内に存在するかどうかを確認します。

存在しない場合は、その要素をMapに追加し、新しい配列に追加します。最終的に、重複のない配列が作成されます。

□サンプルコード7:mapによる重複チェック

function removeDuplicates(array) {
  const uniqueMap = new Map();

  return array.filter((element) => {
    if (!uniqueMap.has(element)) {
      uniqueMap.set(element, true);
      return true;
    }
    return false;
  });
}

// 使用例
const originalArray = [1, 2, 3, 2, 4, 1, 5];
const uniqueArray = removeDuplicates(originalArray);
console.log(uniqueArray);

実行結果

[1, 2, 3, 4, 5]

このサンプルコードでは、removeDuplicates関数内で新しいMapオブジェクトuniqueMapを作成しています。

元の配列originalArrayの要素を1つずつチェックし、uniqueMapにその要素が存在しない場合(hasメソッドがfalseを返す場合)、その要素をuniqueMapに追加し、filterメソッドがtrueを返します。

これにより、重複のない要素だけが新しい配列に追加されます。

mapを使った重複チェックは、効率的で高速な方法です。

特に、大規模な配列に対して使用する場合に有効です。

ただし、Mapオブジェクトを使用するため、コードがやや複雑になる可能性があります。

●オブジェクトの重複チェック手法

JavaScriptのオブジェクトは、キーと値のペアを格納するデータ構造です。

オブジェクトの重複チェックは、配列とは少し異なるアプローチが必要です。

オブジェクトの重複チェックでは、キーの一意性に着目します。

オブジェクトの重複チェックを行う際、SetとObject.entriesを組み合わせる方法が効果的です。

SetはES6で導入された、一意な値のコレクションを表すオブジェクトです。

Object.entriesは、オブジェクトのキーと値のペアを配列として返すメソッドです。

では、SetとObject.entriesを使ったオブジェクトの重複チェックの方法を詳しく見ていきましょう。

○手法8:SetとObject.entriesを使う方法

SetとObject.entriesを使ったオブジェクトの重複チェックの手順は、次の通りです。

  1. Object.entriesを使って、オブジェクトのキーと値のペアを配列に変換する
  2. 配列をSetオブジェクトに変換し、重複を削除する
  3. Setオブジェクトから配列に変換し、Object.fromEntriesを使ってオブジェクトに戻す

この手順を実行することで、重複のないオブジェクトを得ることができます。

□サンプルコード8:SetとObject.entriesによる重複削除

function removeDuplicates(object) {
  return Object.fromEntries(new Set(Object.entries(object)));
}

// 使用例
const originalObject = {
  a: 1,
  b: 2,
  c: 3,
  d: 2,
  e: 1,
};
const uniqueObject = removeDuplicates(originalObject);
console.log(uniqueObject);

実行結果

{a: 1, b: 2, c: 3}

このサンプルコードでは、removeDuplicates関数内で、まずObject.entriesを使ってオブジェクトのキーと値のペアを配列に変換しています。

次に、その配列をSetオブジェクトに変換することで、重複が自動的に削除されます。

最後に、SetオブジェクトをObject.fromEntriesを使ってオブジェクトに戻しています。

SetとObject.entriesを使う方法は、シンプルで簡潔なコードで実装できる上に、パフォーマンスも優れています。

大規模なオブジェクトに対しても効率的に重複削除を行うことができます。

ただし、この方法では、オブジェクトのキーが文字列または Symbol である必要があります。

キーが他のデータ型である場合、別の方法を検討する必要があります。

●重複チェック時の注意点

JavaScriptで重複チェックを行う際、いくつか注意すべき点があります。

重複チェックの手法を正しく理解し、適切に使用することが重要です。

ここでは、参照の同一性と値の同一性の違い、そしてパフォーマンスの考慮について説明します。

これらの注意点を理解することで、より効果的で効率的な重複チェックが可能になります。

では、早速、参照の同一性と値の同一性の違いから見ていきましょう。

○参照の同一性と値の同一性

JavaScriptでは、変数はプリミティブ型(数値、文字列、ブール値など)とオブジェクト型(配列、オブジェクト、関数など)に分類されます。

重複チェックを行う際、参照の同一性と値の同一性の違いを理解しておく必要があります。

プリミティブ型の変数は、値そのものを格納します。

したがって、プリミティブ型の変数の比較は、値の同一性で行われます。

一方、オブジェクト型の変数は、オブジェクトへの参照を格納します。

オブジェクト型の変数の比較は、参照の同一性で行われます。

例えば、次のコードを見てみましょう。

const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr1 === arr2); // false

この例では、arr1とarr2は同じ要素を持つ配列ですが、それぞれ別のオブジェクトへの参照を持っています。

したがって、参照の同一性による比較(===)ではfalseになります。

重複チェックを行う際、参照の同一性と値の同一性の違いを考慮する必要があります。

特に、オブジェクト型の要素を含む配列やオブジェクトの重複チェックでは注意が必要です。

必要に応じて、ディープコピーや再帰的な比較を行うことを検討しましょう。

○パフォーマンスの考慮

重複チェックのパフォーマンスは、データの量や使用する手法によって大きく異なります。

特に、大規模なデータセットを扱う場合、パフォーマンスの考慮が重要になります。

例えば、配列の重複チェックでは、Setを使う方法が最もパフォーマンスが良いとされています。

一方、filterやincludesを使う方法は、配列のサイズが大きくなるとパフォーマンスが悪化する傾向があります。

パフォーマンスを改善するために、次のような工夫を検討できます。

  • 可能な限り、Setを使う方法を選択する
  • 大規模なデータセットを分割し、部分的に重複チェックを行う
  • 重複チェックの頻度を減らす(例:データの追加時のみ重複チェックを行う)
  • パフォーマンスが重要な場合、ライブラリやフレームワークの使用を検討する

パフォーマンスの考慮は、アプリケーションの要件や環境によって異なります。

重複チェックの手法を選択する際、パフォーマンスとコードの可読性のバランスを取ることが重要です。

●重複チェックの実践的な使用例

これまで、JavaScriptにおける重複チェックの手法や注意点について詳しく説明してきました。

でも、実際にどのようなシーンで重複チェックが役立つのか、具体的なイメージがわきにくいかもしれません。

そこで、このセクションでは、重複チェックの実践的な使用例を2つ紹介します。

これらの例を通して、重複チェックがどのように実務で活用されているのかを理解していきましょう。

○ユーザー登録時の重複チェック

ウェブアプリケーションでユーザー登録機能を実装する際、重複チェックは欠かせません。

特に、ユーザーIDやメールアドレスの重複は、システムの整合性を損ねる可能性があります。

例えば、ユーザー登録フォームで入力されたメールアドレスが既に登録されていないかをチェックする場合、次のようなコードを使用できます。

function isEmailUnique(email, registeredEmails) {
  return !registeredEmails.includes(email);
}

// 使用例
const registeredEmails = ['user1@example.com', 'user2@example.com', 'user3@example.com'];
const newEmail = 'user4@example.com';

if (isEmailUnique(newEmail, registeredEmails)) {
  console.log('このメールアドレスは登録可能です。');
} else {
  console.log('このメールアドレスは既に登録されています。');
}

実行結果

このメールアドレスは登録可能です。

このサンプルコードでは、isEmailUnique関数を使ってメールアドレスの重複チェックを行っています。

registeredEmailsは既に登録されているメールアドレスの配列、newEmailは新しく登録しようとしているメールアドレスです。

includesメソッドを使って、newEmailがregisteredEmails内に存在するかどうかを確認しています。

存在しない場合はtrueを返し、存在する場合はfalseを返します。

このように、重複チェックを行うことで、ユーザー登録の際に重複したメールアドレスが登録されることを防ぐことができます。

同様の手法を用いて、ユーザーIDの重複チェックも実装できます。

○ECサイトでの商品重複チェック

ECサイトでは、商品の重複登録を防ぐために重複チェックが使用されます。

商品の重複は、在庫管理や検索機能に悪影響を及ぼす可能性があります。

例えば、商品の重複をチェックする場合、次のようなコードを使用できます。

function isProductUnique(productId, registeredProducts) {
  return !registeredProducts.some((product) => product.id === productId);
}

// 使用例
const registeredProducts = [
  { id: 1, name: 'Product 1' },
  { id: 2, name: 'Product 2' },
  { id: 3, name: 'Product 3' },
];
const newProduct = { id: 4, name: 'Product 4' };

if (isProductUnique(newProduct.id, registeredProducts)) {
  console.log('この商品は登録可能です。');
} else {
  console.log('この商品は既に登録されています。');
}

実行結果

この商品は登録可能です。

このサンプルコードでは、isProductUnique関数を使って商品の重複チェックを行っています。

registeredProductsは既に登録されている商品の配列、newProductは新しく登録しようとしている商品のオブジェクトです。

someメソッドを使って、registeredProducts内に新しい商品のIDと一致するIDを持つ商品が存在するかどうかを確認しています。

存在しない場合はtrueを返し、存在する場合はfalseを返します。

このように、重複チェックを行うことで、ECサイトでの商品の重複登録を防ぐことができます。

まとめ

本記事では、JavaScriptにおける重複チェックの手法を8つ紹介しました。

JavaScriptでの重複チェックは、アプリケーションの品質向上に欠かせない技術です。

本記事で紹介した手法や使用例を活用し、効果的で効率的な重複チェックを実装することで、開発スキルを向上させましょう。