TypeScriptで重複を削除する10の手法 – Japanシーモア

TypeScriptで重複を削除する10の手法

TypeScriptを使って重複を効率的に削除するイラストTypeScript
この記事は約36分で読めます。

 

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

このサービスは複数のSSPによる協力の下、運営されています。

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

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

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

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

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

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

はじめに

私たちは日常的に多くのデータを取り扱います。

そのデータ内には重複するものが存在することが多々あります。

例えば、ユーザーリストや商品リストなど、重複するデータは不要な情報を持っており、処理速度の低下や誤った分析結果をもたらす可能性があります。

このような問題を避けるため、適切な手法で重複を削除することが非常に重要です。

TypeScriptは、このような重複データの削除に対して、多くのツールや方法を提供しています。

標準のライブラリや組み込み関数を活用することで、効率的に重複を削除することができます。

また、外部のライブラリやカスタム関数を利用することで、より高度な重複削除も可能です。

本記事では、その中でも特に実践的で役立つ10の手法をピックアップし、サンプルコードと共に徹底的に解説します。

それぞれの手法には、その特性や利点、そして使用シーンに応じた応用例も交えて紹介しますので、ぜひ最後までお読みください。

●TypeScriptでの重複削除の基本

重複データは、データの正確性や効率性を低下させる原因となります。

TypeScriptを使用して重複データを効率的に削除することで、データの品質を保つことができます。

また、TypeScriptの型安全性を活かすことで、より安全にデータ操作を行うことが可能です。

このコードでは、TypeScriptの基本的なデータ操作を使って重複を削除する方法を表しています。

この例では、配列の要素をフィルタリングして重複を除外しています。

// 重複したデータを含む配列を定義
const duplicatedArray: number[] = [1, 2, 2, 3, 4, 4, 5];

// Setオブジェクトを使用して重複を削除
const uniqueArray: number[] = [...new Set(duplicatedArray)];

console.log(uniqueArray); // [1, 2, 3, 4, 5]

上記のサンプルコードでは、Setオブジェクトを利用して配列の重複を簡単に削除しています。

Setオブジェクトは、重複を許さないコレクションであるため、これを利用することで、簡潔に重複を削除することができます。

最後に、スプレッド構文...を使用して、Setオブジェクトを配列に変換しています。

このコードを実行すると、consoleに[1, 2, 3, 4, 5]という結果が出力されることを確認できます。

これにより、Setを使用することで、重複を含む配列から簡単に重複を削除した新しい配列を作成できることがわかります。

●10の重複削除手法とサンプルコード

TypeScriptは、JavaScriptのスーパーセットとして、強力な型機能を提供しています。

この特性を活かして、TypeScriptでのデータの重複削除に関するさまざまな手法を紹介します。

今回は10の方法を取り上げ、それぞれのサンプルコードとともに徹底的に解説していきます。

○サンプルコード1:Setを利用した基本的な重複削除

このコードでは、JavaScriptでもよく利用されるSetを使って、配列から重複するデータを取り除く方法を表しています。

この例では、文字列の配列から重複する要素を取り除いています。

const data: string[] = ['apple', 'banana', 'apple', 'orange'];
const uniqueData: string[] = [...new Set(data)];
console.log(uniqueData);

このコードでは、まずdataという文字列の配列を用意しています。

そして、この配列をSetのコンストラクタに渡して新しいSetオブジェクトを生成します。

このとき、Setは自動的に重複する要素を取り除いてくれます。

その後、スプレッド構文(...)を使って、Setオブジェクトを再び配列に変換しています。

このコードを実行すると、コンソールには['apple', 'banana', 'orange']と表示され、dataから重複する'apple'が取り除かれた新しい配列が得られます。

この方法は、簡潔であり、また処理速度も速いのが特徴です。

ただし、オブジェクトや配列のような参照型のデータを扱う場合には、この方法だけでは期待する結果が得られないことがあります。

その場合は、他の手法を組み合わせるか、参照の代わりに値の比較を行う必要があります。

○サンプルコード2:filterメソッドを使った重複削除

重複の削除は、データの整合性を保つための重要なステップです。

TypeScriptでの重複削除は多くの方法が存在しますが、今回はArrayのメソッドであるfilterを用いた手法に焦点を当てて説明します。

このコードでは、Arrayのfilterメソッドを使って重複を削除する手法を表しています。

この例では、配列内の要素を順に調べ、その要素が初めて登場した位置と現在の要素の位置が一致するかどうかを判定しています。

この判定により、重複する要素は除外されることになります。

const removeDuplicatesWithFilter = (arr: any[]): any[] => {
  return arr.filter((element, index) => {
    return arr.indexOf(element) === index;
  });
};

// 使用例
const sampleArray = [1, 2, 3, 2, 5, 1, 6, 7];
const resultArray = removeDuplicatesWithFilter(sampleArray);
console.log(resultArray); // [1, 2, 3, 5, 6, 7]

上記のコードを見てみると、removeDuplicatesWithFilterという関数を定義しています。

この関数は、引数として配列arrを受け取り、filterメソッドを使ってその配列内の重複を削除した結果を返しています。

実際にこのコードを実行すると、sampleArray内の重複が削除された新しい配列がresultArrayに代入されます。

そして、その結果として、[1, 2, 3, 5, 6, 7]がコンソールに出力されます。

しかし、この手法は大きなデータに対して非効率であることに注意が必要です。

というのも、indexOfメソッドは毎回配列を先頭から走査するため、配列の要素数が増えると処理時間が増大します。

もし、オブジェクトの配列で特定のキーの値に基づいて重複を削除したい場合は、次のようなコードを利用できます。

type SampleObject = {
  id: number;
  name: string;
};

const removeDuplicatesFromObjects = (arr: SampleObject[]): SampleObject[] => {
  return arr.filter((element, index, selfArray) => {
    return (
      index ===
      selfArray.findIndex((obj) => {
        return obj.id === element.id;
      })
    );
  });
};

// 使用例
const sampleObjectArray: SampleObject[] = [
  { id: 1, name: "A" },
  { id: 2, name: "B" },
  { id: 2, name: "B" },
  { id: 3, name: "C" },
];

const resultObjectArray = removeDuplicatesFromObjects(sampleObjectArray);
console.log(resultObjectArray); 
// [{ id: 1, name: 'A' }, { id: 2, name: 'B' }, { id: 3, name: 'C' }]

この例では、オブジェクトの配列内のidキーの値を基に重複を削除しています。

実際に上記のコードを実行すると、sampleObjectArrayの重複が削除された新しい配列がresultObjectArrayに代入され、その結果[{ id: 1, name: 'A' }, { id: 2, name: 'B' }, { id: 3, name: 'C' }]がコンソールに出力されます。

○サンプルコード3:reduceメソッドを活用したアプローチ

TypeScriptを使用する際、配列の重複要素を削除する一つの効果的な方法として、reduceメソッドを活用するアプローチがあります。

このコードでは、reduceメソッドを使って配列の要素を一つずつ処理し、新しい配列を生成することで重複要素を削除しています。

この例では、初めて現れた要素のみを新しい配列に追加し、それ以外の要素は無視することで重複を削除しています。

const numbers = [1, 2, 3, 2, 1, 4, 5, 3];

const uniqueNumbers = numbers.reduce((acc, cur) => {
    // 現在の要素が累積された配列に存在しない場合、要素を追加する
    if (!acc.includes(cur)) {
        acc.push(cur);
    }
    return acc;
}, [] as number[]);

console.log(uniqueNumbers); // [1, 2, 3, 4, 5]

このサンプルコードのキーポイントは、reduceメソッドの第一引数として指定されたコールバック関数です。

この関数は、累積値(最初は空の配列[])と現在の要素を引数として受け取ります。

そして、現在の要素が累積された配列に存在しない場合にのみ、その要素を配列に追加します。

この手法によって、新しい配列には重複しない要素のみが追加されることになります。

このコードを実行すると、uniqueNumbersという名前の新しい配列が生成され、その中にはnumbers配列の重複を削除した要素のみが格納されます。

結果として、[1, 2, 3, 4, 5]という配列が出力されるでしょう。

応用例として、オブジェクトの配列を扱う場合も考えてみましょう。

例えば、次のようなオブジェクトの配列があり、その中のidプロパティに基づいて重複を削除したい場合、どのようにすればよいでしょうか。

const users = [
    { id: 1, name: "Taro" },
    { id: 2, name: "Hanako" },
    { id: 1, name: "Taro" },
    { id: 3, name: "Jiro" }
];

const uniqueUsers = users.reduce((acc, cur) => {
    if (!acc.some(user => user.id === cur.id)) {
        acc.push(cur);
    }
    return acc;
}, [] as { id: number; name: string }[]);

console.log(uniqueUsers);

上記のサンプルコードでは、someメソッドを使用して、累積された配列内のオブジェクトのidプロパティが現在のオブジェクトのidプロパティと一致するかどうかをチェックしています。

一致するものが存在しない場合にのみ、現在のオブジェクトを新しい配列に追加しています。

この方法を用いると、オブジェクトの配列から重複するオブジェクトを効率的に削除することができます。

○サンプルコード4:Mapを使用したキーと値の重複削除

TypeScriptを使用してデータから重複を削除する方法として、Mapを利用するアプローチがあります。

この手法は、特にキーと値のペアを持つデータ構造において、キーの重複を避けつつ、最新の値を保持することができます。

このコードでは、Mapオブジェクトを使用してキーと値のペアから重複を削除する方法を表しています。

この例では、配列内のオブジェクトの特定のプロパティをキーとして使用し、重複を削除しながら最新のオブジェクトをMapに格納しています。

interface Person {
    id: number;
    name: string;
    age: number;
}

const people: Person[] = [
    { id: 1, name: "山田", age: 30 },
    { id: 2, name: "佐藤", age: 25 },
    { id: 1, name: "山田", age: 31 }, // idが重複
    { id: 3, name: "鈴木", age: 29 },
];

const uniqueMap = new Map<number, Person>();

people.forEach(person => {
    // idをキーとして、重複がある場合は上書きされる
    uniqueMap.set(person.id, person);
});

const uniquePeople = Array.from(uniqueMap.values());
console.log(uniquePeople);

このサンプルコードを実行すると、次の結果を得られる。

idが1の山田さんの情報が2つ存在しているが、Mapを利用することで、最新の情報(31歳のデータ)だけが残されています。

そのため、出力される配列には、山田さんのデータが1つだけ含まれる。

[
    { id: 1, name: "山田", age: 31 },
    { id: 2, name: "佐藤", age: 25 },
    { id: 3, name: "鈴木", age: 29 },
]

また、Mapを利用した重複削除は、オブジェクトの特定のプロパティだけでなく、他の条件でも利用可能です。

例えば、名前が同じ場合に重複とみなすようなケースも考えられます。

const uniqueByName = new Map<string, Person>();

people.forEach(person => {
    uniqueByName.set(person.name, person);
});

const resultByName = Array.from(uniqueByName.values());
console.log(resultByName);

このコードでは、名前を基に重複削除を行います。

結果として、名前が同じデータは最新のものだけが保持され、他は削除されます。

○サンプルコード5:型を活用しての重複チェック

このコードではTypeScriptの型システムを使って、オブジェクトの重複を効率的にチェックする方法を表しています。

この例では、特定のプロパティを持つオブジェクトの配列を考え、その中で重複するオブジェクトを検出しています。

interface Person {
    id: number;
    name: string;
}

const persons: Person[] = [
    { id: 1, name: "田中" },
    { id: 2, name: "山田" },
    { id: 3, name: "鈴木" },
    { id: 1, name: "田中" },
];

const checkDuplicate = (arr: Person[]): boolean => {
    const ids: { [key: number]: boolean } = {};
    for (const person of arr) {
        if (ids[person.id]) {
            return true;  // 重複あり
        }
        ids[person.id] = true;
    }
    return false;  // 重複なし
};

const hasDuplicate = checkDuplicate(persons);
if (hasDuplicate) {
    console.log("重複しているデータが存在します。");
} else {
    console.log("全てのデータはユニークです。");
}

このコードでは、Personというインターフェースを定義し、その型を持つオブジェクトの配列personsを作成しています。

そして、checkDuplicate関数を使ってこの配列の中でidが重複しているかどうかをチェックしています。

具体的には、idsというオブジェクトを使い、配列を順に走査しながら各idの存在を記録していきます。

もし既にそのidが記録されていれば、それは重複とみなし、trueを返すことで重複を検出します。

このコードを実行すると、”重複しているデータが存在します。”という結果が表示されます。

なぜなら、persons配列の中にidが1の”田中”さんが2回登場しているからです。

○サンプルコード6:カスタム関数を使った詳細な重複削除

TypeScriptでは、ArrayのメソッドやSetなどの組み込みオブジェクトを使用して重複削除を行うことができます。

しかし、特定の条件に基づいて重複を判定する必要がある場合や、詳細なロジックを組み込みたい場合は、カスタム関数を使用するのが適しています。

このコードではカスタム関数を使って、特定の条件を持つオブジェクトの配列からの重複を削除する方法を表しています。

この例では、nameプロパティを基準にしてオブジェクトの重複をチェックしています。

type Person = {
    id: number;
    name: string;
    age: number;
};

const persons: Person[] = [
    {id: 1, name: "Taro", age: 25},
    {id: 2, name: "Hanako", age: 30},
    {id: 3, name: "Taro", age: 22},
    {id: 4, name: "Yoko", age: 27},
];

const removeDuplicateByName = (array: Person[]): Person[] => {
    const unique: Person[] = [];
    const names: string[] = [];

    for (const item of array) {
        if (!names.includes(item.name)) {
            names.push(item.name);
            unique.push(item);
        }
    }
    return unique;
};

const result = removeDuplicateByName(persons);
console.log(result);

この例の重点は、二つの配列を使っています。

一つはunique配列で、重複しないオブジェクトを保存します。

もう一つはnames配列で、すでに処理されたオブジェクトのnameプロパティの値を保存して、後続のオブジェクトが重複しているかどうかをチェックします。

上記のコードを実行すると、次のような結果を得ることができます。

オブジェクトの配列から、”Taro”というnameを持つ2つのオブジェクトが存在しますが、カスタム関数によって1つにまとめられています。

そのため、出力される結果は3つのオブジェクトのみとなります。

[
  { id: 1, name: 'Taro', age: 25 },
  { id: 2, name: 'Hanako', age: 30 },
  { id: 4, name: 'Yoko', age: 27 }
]

この方法のメリットは、カスタム関数内でのロジックを変更するだけで、さまざまな条件に基づく重複の削除を柔軟に対応できることです。

例えば、年齢を基準にした重複の削除や、複数のプロパティを考慮した複雑な重複の削除など、具体的な要件に合わせて関数をカスタマイズすることが可能です。

このカスタム関数をさらに進化させるためのヒントとして、Genericsを使用して、さまざまなオブジェクトのタイプに適用できるような汎用的な関数を作成することも考えられます。

Genericsを使用することで、特定のオブジェクトの型に限定されず、様々なオブジェクトの型に適用することができるため、より幅広いシーンでの利用が可能となります。

○サンプルコード7:外部ライブラリLodashを利用した方法

TypeScriptにおける重複データの削除に関しては、外部のライブラリを利用する方法も非常に有用であることをご紹介します。

特に「Lodash」というJavaScriptのユーティリティライブラリは、多岐にわたる機能を持っており、その中でも重複データの削除は簡単に行えます。

Lodashは、JavaScriptを更に使いやすくするためのユーティリティライブラリであり、配列やオブジェクト、文字列などの操作を簡単に行うことができます。

また、TypeScriptとも非常に相性がよく、型の安全性を保持したまま多くの操作を行うことができます。

このコードでは、Lodashのuniqメソッドを使用して、配列内の重複を削除する手法を表しています。

この例では、文字列の配列を重複なくする操作を行っています。

import _ from 'lodash';

const duplicatedArray: string[] = ["apple", "banana", "apple", "grape", "banana"];
const uniqueArray: string[] = _.uniq(duplicatedArray);

console.log(uniqueArray);

このコードを実行すると、uniqueArrayの中身は["apple", "banana", "grape"]となり、重複していた"apple""banana"が一つずつに削除された状態で出力されます。

しかし、uniqメソッドは単純な重複の削除のみに対応しています。

もし、オブジェクトの配列や、より複雑な条件での重複削除を行いたい場合は、LodashのuniqByuniqWithといったメソッドを利用すると良いでしょう。

例えば、次のようにオブジェクトの配列において、特定のプロパティを基準にして重複を削除することができます。

type Fruit = {
    id: number;
    name: string;
};

const fruits: Fruit[] = [
    { id: 1, name: "apple" },
    { id: 2, name: "banana" },
    { id: 1, name: "apple" },
    { id: 3, name: "grape" },
    { id: 2, name: "banana" }
];

const uniqueFruits: Fruit[] = _.uniqBy(fruits, 'id');

console.log(uniqueFruits);

上記のコードを実行すると、idプロパティを基準にした重複データが削除されたuniqueFruitsが出力されます。

このように、Lodashを利用することで、様々な条件での重複データの削除を簡単かつ効率的に行うことができます。

また、Lodashには他にも多くのユーティリティメソッドが用意されており、データ操作に関する多くの課題を簡潔に解決することができるので、是非とも活用してみることをおすすめします。

○サンプルコード8:for-ofループを使った独自の方法

TypeScriptを用いて重複を削除する方法は多岐にわたります。

ここでは、for-ofループを使った独自の方法を用いて配列から重複を削除する方法を解説いたします。

特にfor-ofループは、配列の各要素を直接取り出して処理するのに便利な構文です。

このコードではfor-ofループと配列のindexOfメソッドを組み合わせて、重複する要素を削除するコードを表しています。

この例では元の配列から順に要素を取り出し、結果を保存する新しい配列にその要素がすでに存在していない場合にだけ追加しています。

const removeDuplicatesUsingForOf = (arr: number[]): number[] => {
  let uniqueArray: number[] = [];
  for (const element of arr) {
    if (uniqueArray.indexOf(element) === -1) {
      uniqueArray.push(element);
    }
  }
  return uniqueArray;
};

// 使用例
const sampleArray = [1, 2, 2, 3, 4, 4, 5];
const resultArray = removeDuplicatesUsingForOf(sampleArray);
console.log(resultArray);  // [1, 2, 3, 4, 5]

上記のサンプルコードを実行すると、sampleArrayの重複を取り除いた新しい配列resultArrayが得られます。

この結果として、コンソールには[1, 2, 3, 4, 5]という配列が表示されることが期待されます。

この手法の良い点は、コードが直感的で理解しやすいことです。

ただし、大きなデータに対してこの手法を使用すると、パフォーマンス上の問題が生じる可能性があります。

なぜなら、indexOfメソッドが毎回配列全体をスキャンするため、処理時間が増大する可能性があるからです。

もしオブジェクトの配列で重複をチェックしたい場合、プロパティの値を基にしてチェックする必要があります。

オブジェクトのidプロパティを基に重複を削除する方法のサンプルコードを紹介します。

type MyObject = {
  id: number;
  name: string;
};

const removeDuplicateObjects = (arr: MyObject[]): MyObject[] => {
  let uniqueArray: MyObject[] = [];
  for (const obj of arr) {
    if (!uniqueArray.some(uniqueObj => uniqueObj.id === obj.id)) {
      uniqueArray.push(obj);
    }
  }
  return uniqueArray;
};

// 使用例
const objectArray: MyObject[] = [
  { id: 1, name: 'A' },
  { id: 2, name: 'B' },
  { id: 2, name: 'B' },
  { id: 3, name: 'C' }
];
const resultObjectArray = removeDuplicateObjects(objectArray);
console.log(resultObjectArray);  // [{ id: 1, name: 'A' }, { id: 2, name: 'B' }, { id: 3, name: 'C' }]

この応用例では、オブジェクトの配列の重複を削除する方法を表しています。

この方法も、前述の基本例と同様に、特定の条件下ではパフォーマンスの問題が生じる可能性があることに注意が必要です。

○サンプルコード9:findIndexとspliceを組み合わせた方法

TypeScriptを用いた重複データの削除にはさまざまなアプローチがあります。

ここでは、findIndexspliceメソッドを組み合わせた方法を解説します。

このコードでは、findIndexメソッドを使って配列内での該当する要素の最初のインデックスを取得し、spliceメソッドを用いてその要素を削除することで重複を解消します。

この例では、数値の配列を対象として、重複した要素を削除する処理を実装しています。

// 重複要素を持つ配列を定義
const numbers: number[] = [1, 2, 2, 3, 4, 4, 5];

// 重複要素を削除する関数を定義
function removeDuplicates(arr: number[]): number[] {
    for (let i = 0; i < arr.length; i++) {
        let j: number;

        // 同じ要素が存在する場合、その要素の位置を取得
        while ((j = arr.indexOf(arr[i], i + 1)) !== -1) {
            arr.splice(j, 1);  // 重複要素を削除
        }
    }

    return arr;
}

// 重複要素を削除した結果を出力
const result: number[] = removeDuplicates(numbers);
console.log(result);

上記のコードを実行すると、[1, 2, 3, 4, 5]という結果が得られるでしょう。

indexOfメソッドを用いて、配列内で指定した要素と同じ要素が存在する場合、その要素の位置を取得しています。

そして、その位置の要素をspliceメソッドを使用して削除しています。

また、オブジェクトの配列にも同様の手法を適用することができます。

この例では、名前を持つオブジェクトの配列から、名前が重複するオブジェクトを削除します。

type Person = {
    name: string;
}

const persons: Person[] = [
    { name: "Taro" },
    { name: "Jiro" },
    { name: "Taro" },
    { name: "Saburo" }
];

function removeDuplicatePersons(arr: Person[]): Person[] {
    for (let i = 0; i < arr.length; i++) {
        let j: number;

        while ((j = arr.findIndex((person) => person.name === arr[i].name, i + 1)) !== -1) {
            arr.splice(j, 1);
        }
    }

    return arr;
}

const uniquePersons: Person[] = removeDuplicatePersons(persons);
console.log(uniquePersons);

このコードを実行すると、[{ name: "Taro" }, { name: "Jiro" }, { name: "Saburo" }]のように、名前が重複するオブジェクトが削除された結果が出力されるでしょう。

○サンプルコード10:includesメソッドを用いたシンプルな手法

TypeScriptでの配列や文字列の重複チェックや削除には、様々な手法が存在しますが、こちらではincludesメソッドを活用した非常にシンプルな手法を取り上げます。

このコードでは、includesメソッドを使って配列内に特定の要素が存在するかを確認し、その結果に基づいて重複した要素を削除する方法を表しています。

// このコードではincludesメソッドを用いて、配列内の重複を削除する機能を実装しています。
const removeDuplicatesUsingIncludes = (arr: any[]): any[] => {
  let uniqueArray: any[] = [];

  for(let i = 0; i < arr.length; i++) {
    if(!uniqueArray.includes(arr[i])) {
      uniqueArray.push(arr[i]);
    }
  }
  return uniqueArray;
}

const sampleArray = [1, 2, 2, 3, 4, 4, 5];
const result = removeDuplicatesUsingIncludes(sampleArray);
console.log(result);  // 重複を削除した後の配列が出力されます。

この例では、removeDuplicatesUsingIncludes関数を定義し、引数として与えられた配列arrの各要素について、新しい配列uniqueArrayにその要素がすでに存在するかどうかをincludesメソッドを用いて確認しています。

もし存在しない場合、その要素をuniqueArrayに追加します。

この方法の特徴は、コードの読みやすさとシンプルさにあります。

しかし、大きなデータセットに対してはパフォーマンスの面で最適ではない場合もあります。

そのため、データの量や利用シーンに応じて、適切な手法を選択することが重要です。

上記のサンプルコードを実行すると、sampleArray内の重複した数字が削除され、新しい配列が出力されます。

具体的には、[1, 2, 2, 3, 4, 4, 5]という配列が、[1, 2, 3, 4, 5]という重複のない配列に変換されます。

また、文字列の中にも同じ文字が複数回出現する場合があります。

この手法は、文字列に対しても適用可能です。

文字列内の重複した文字を削除する例を紹介します。

const removeDuplicateChars = (str: string): string => {
  let uniqueString = "";

  for(let i = 0; i < str.length; i++) {
    if(!uniqueString.includes(str[i])) {
      uniqueString += str[i];
    }
  }
  return uniqueString;
}

const sampleString = "aabbccdd";
const resultString = removeDuplicateChars(sampleString);
console.log(resultString);  // 重複を削除した後の文字列が出力されます。

この例では、removeDuplicateChars関数を定義し、文字列strの各文字について、新しい文字列uniqueStringにその文字がすでに存在するかどうかを確認し、存在しない場合に追加しています。

このコードを実行すると、”aabbccdd”という文字列が、”abcd”という重複のない文字列に変換されます。

●応用例とサンプルコード

応用例として、実際の開発では、単純な数値や文字列だけでなく、オブジェクトなどの複雑なデータ構造を持つ要素の重複削除が必要になることがあります。

TypeScriptの強力な型システムを利用することで、オブジェクトの配列のような複雑なデータでも、安全かつ効率的に重複データを取り扱うことが可能です。

○サンプルコード11:オブジェクト内の重複データを削除する方法

このコードでは、オブジェクトの配列から特定のプロパティを基準にして重複データを削除する方法を表しています。

この例では、idプロパティを基準にして重複するオブジェクトを取り除いています。

interface DataObject {
    id: number;
    name: string;
}

const dataArray: DataObject[] = [
    { id: 1, name: "A" },
    { id: 2, name: "B" },
    { id: 2, name: "C" },
    { id: 3, name: "D" }
];

const uniqueDataArray: DataObject[] = dataArray.filter((obj, index, self) =>
    index === self.findIndex((t) => t.id === obj.id)
);
console.log(uniqueDataArray);

このコードを実行すると、uniqueDataArrayの中身は以下のようになります。

[
  { id: 1, name: "A" },
  { id: 2, name: "B" },
  { id: 3, name: "D" }
]

このように、idが2のオブジェクトが重複していたので、最初に出てきたものだけが残り、それ以降の重複するオブジェクトは取り除かれました。

○サンプルコード12:二次元配列での重複データの取り扱い

二次元配列は、配列の中にさらに配列が存在する構造のことを指します。

このような複雑なデータ構造では、一般的な配列とは異なり、重複データの取り扱いが少し難しくなることがあります。

そのため、TypeScriptを使用してこのような二次元配列の重複データを効率的に削除する方法について解説します。

このコードでは、二次元配列内の重複データを検出して、それを削除する方法を表しています。

この例では、最初に重複データを特定するための関数を定義し、その後、その関数を使って実際に二次元配列の重複データを削除します。

// 二次元配列の中の配列を文字列に変換して比較する関数
function isDuplicate(arr: any[][], target: any[]): boolean {
    return arr.some(item => JSON.stringify(item) === JSON.stringify(target));
}

// 二次元配列の中から重複を削除する関数
function removeDuplicatesFrom2DArray(arr: any[][]): any[][] {
    return arr.filter((item, index) => {
        return index === arr.findIndex(t => JSON.stringify(t) === JSON.stringify(item));
    });
}

// サンプルの二次元配列
const sampleArray: any[][] = [
    [1, 2],
    [3, 4],
    [1, 2],
    [5, 6],
    [3, 4]
];

// 重複を削除した後の二次元配列
const resultArray = removeDuplicatesFrom2DArray(sampleArray);
console.log(resultArray);

上記のコードでは、isDuplicate関数とremoveDuplicatesFrom2DArray関数を定義しています。

isDuplicate関数は、指定した配列が二次元配列の中に存在するかどうかを判定するためのもので、removeDuplicatesFrom2DArray関数は実際に重複を削除するためのものです。

最後に、サンプルの二次元配列から重複を削除する例を示しています。

このコードを実行すると、サンプルの二次元配列から重複したデータが効率的に削除され、次のような結果が得られます。

[
  [1, 2],
  [3, 4],
  [5, 6]
]

上記の結果からわかるように、重複していた[1, 2][3, 4]はそれぞれ1つだけ残り、他の重複データは削除されています。

●注意点と対処法

重複データを削除する際には、様々な注意点と対処法が考えられます。

ここでは、TypeScriptを使用して重複を削除する上での主要なポイントについて、詳しく解説いたします。

○データの種類による注意点

このコードでは、データの種類に応じた注意点を紹介しています。

この例では、数値、文字列、オブジェクトなどのデータ型ごとに、どのような特性があり、それに対してどのように重複を削除するかについて説明しています。

❶数値

数値のデータにおいては、精度の問題が考えられる。

例えば、浮動小数点数の比較時には、極小の差異が発生する可能性があるため、近似値での比較が必要となる。

❷文字列

文字列の場合、大文字・小文字の区別、前後の空白の扱いに注意が必要。

特に、国際化を考慮した場合、同じ文字が異なるエンコードで保存される可能性がある。

❸オブジェクト

オブジェクトの比較においては、プロパティの順序やプロトタイプチェーンをどう扱うかが問題となる。

深い比較を行うライブラリの使用も考慮すると良い。

○パフォーマンスの観点からのヒント

このコードでは、パフォーマンスを最適化するためのヒントを紹介しています。

この例では、大量のデータを扱う場合や、繰り返しの処理を行う場合に、どのような点を注意しながらコードを書くべきかを説明しています。

❶ループの最適化

重複の検出と削除を効率的に行うためには、ループの最適化が必要。

特に、ネストされたループを避け、適切なデータ構造を使用することで、計算時間を削減できる。

❷データ構造の選択

SetやMapなどのデータ構造は、重複の検出や削除に適している。

これらを活用することで、効率的なコードを書くことができる。

❸非同期処理の利用

長時間かかる処理の場合、非同期処理を利用してユーザー体験を向上させることができる。

○エッジケースとその対処法

このコードでは、重複削除の際に考慮すべきエッジケースと、それに対する対処法を表しています。

この例では、一般的なケースとは異なる特殊なケースでの重複の扱い方や、それに関連する問題点を解説しています。

❶nullやundefined

データにnullやundefinedが混ざっている場合、これらをどう扱うかが問題となる。

特に、これらの値が意味を持つ場合は、適切に処理を行う必要がある。

❷疑似的な重複

例えば、空の文字列や0、falseなど、異なる値でも同じように評価される場合がある。

これらのケースを適切に処理するための方法や、それを避けるためのアプローチを考慮することが重要。

❸外部データの取り扱い

外部からのデータ入力時には、データの正当性をチェックすることが必要。

不正なデータや予期しないデータ形式によるエラーを避けるための処理を実装することが求められる。

●カスタマイズ方法

TypeScriptでの重複削除は、一般的な手法にとどまらず、さまざまなカスタマイズが可能です。

ここでは、そのカスタマイズ方法をいくつか紹介します。

○重複判定のカスタマイズ

このコードでは、配列内の数字の重複を確認するコードを表しています。

この例では、重複を判定するための条件をカスタマイズして、特定の範囲の数字だけをチェックする方法を表しています。

function 重複判定(配列: number[], 最小値: number, 最大値: number): number[] {
    return 配列.filter((要素, インデックス, 自身) => {
        return 自身.indexOf(要素) === インデックス && 要素 >= 最小値 && 要素 <= 最大値;
    });
}

const 数字の配列 = [1, 2, 2, 3, 4, 5, 6, 6, 7];
const 結果 = 重複判定(数字の配列, 3, 6);
console.log(結果); // [3, 4, 5, 6]

上記のコードでは、最小値3と最大値6の間にある数字の重複だけを判定しています。

結果として、3, 4, 5, 6の4つの数字が重複なしで出力されることがわかります。

○エラーハンドリングのカスタマイズ

このコードでは、配列内の文字列の重複を確認するコードを表しています。

この例では、エラーハンドリングをカスタマイズして、空の文字列やnull値が配列内にある場合はエラーメッセージを出力する方法を表しています。

function 重複確認(配列: string[]): string[] {
    if (配列.some(要素 => 要素 === "" || 要素 === null)) {
        throw new Error("空の文字列やnull値は許可されていません");
    }
    return 配列.filter((要素, インデックス, 自身) => {
        return 自身.indexOf(要素) === インデックス;
    });
}

try {
    const 文字列の配列 = ["apple", "orange", "apple", ""];
    const 結果 = 重複確認(文字列の配列);
    console.log(結果);
} catch (エラー) {
    console.error(エラー.message);
}

上記のコードを実行すると、”空の文字列やnull値は許可されていません”というエラーメッセージが出力されることがわかります。

まとめ

TypeScriptを使用する際の重複データの削除方法には多様なアプローチが存在します。

この記事では、初心者から中級者までのTypeScriptユーザーが実際の開発で適用できる10の重複削除手法を詳しく解説しました。

以上の手法を駆使することで、TypeScriptでのプログラミングがより効率的かつ安全になります。

特に、TypeScriptの型システムを活用する方法は、他のプログラミング言語やフレームワークでは実現困難なアプローチを可能にします。

また、応用例や注意点、カスタマイズ方法についても詳しく触れていますので、日常の開発で直面する問題に対するソリューションとして活用していただければと思います。

TypeScriptを使った開発を進める上で、重複削除の技術は欠かせないものです。

この記事を参考に、よりクリーンで効率的なコードを書くための知識を深めてください。