【JavaScript】連想配列の重複排除

## はじめに
JavaScriptの連想配列を加工してみようと思い、いろいろ試してみました。

そこで連想配列か配列か、どちらを使えば効率的に課題をクリアできるか考えたので、その過程をまとめます。

## 環境
Node.js（v20.11.0）

## 問題
* 次のような連想配列がある

```javascript
[
  { key: 'A', date: '2023/05/01', regiDate: '2023/04/25' },
  { key: 'B', date: '2023/05/02', regiDate: '2023/04/26' },
  { key: 'C', date: '2023/05/03', regiDate: '2023/04/27' },
  { key: 'A', date: '2023/05/04', regiDate: '2023/04/28' },
  { key: 'D', date: '2023/05/05', regiDate: '2023/04/29' },
  { key: 'B', date: '2023/05/02', regiDate: '2023/04/30' },
  { key: 'E', date: '2023/05/07', regiDate: '2023/05/01' },
  { key: 'D', date: '2023/05/08', regiDate: '2023/05/02' },
  { key: 'C', date: '2023/05/09', regiDate: '2023/05/03' },
  { key: 'A', date: '2023/05/04', regiDate: '2023/05/04' }
];
```

* この連想配列を次の条件に従い、重複排除するプログラムを作成せよ

**【条件】**
* ①同じkeyの値を持つ要素を、一つだけ配列に残す
* ②dataが最新の要素を残す
* ③dataが同じ場合は、regiDateが最新の要素を残す

## 解法
* forループ内のif文で、配列に含む値を決定する

```javascript: assignment.js
/*
連想配列を以下の条件に従って重複排除した形に加工するJavaScriptプログラムを作成。

【条件】
1. 同じ "key" の値を持つ要素を、1つだけ配列に残す。
2. "date" が最新の要素を残す。
3. "date" が同じ場合は、"regiDate" が最新の要素を残す。
*/

var data = [
  { key: 'A', date: '2023/05/01', regiDate: '2023/04/25' },
  { key: 'B', date: '2023/05/02', regiDate: '2023/04/26' },
  { key: 'C', date: '2023/05/03', regiDate: '2023/04/27' },
  { key: 'A', date: '2023/05/04', regiDate: '2023/04/28' },
  { key: 'D', date: '2023/05/05', regiDate: '2023/04/29' },
  { key: 'B', date: '2023/05/02', regiDate: '2023/04/30' },
  { key: 'E', date: '2023/05/07', regiDate: '2023/05/01' },
  { key: 'D', date: '2023/05/08', regiDate: '2023/05/02' },
  { key: 'C', date: '2023/05/09', regiDate: '2023/05/03' },
  { key: 'A', date: '2023/05/04', regiDate: '2023/05/04' }
];

var result = {};

for (var i = 0; i < data.length; i++) {
  var item = data[i];
  if (!result[item.key] || item.date > result[item.key].date || (item.date === result[item.key].date && item.regiDate > result[item.key].regiDate)) {
    result[item.key] = item;
  }
}

var output = Object.values(result);
console.log(output);
```

* forループを使ってdata配列の各要素(item)を順番の処理します
* if文では、以下の三つの条件のいずれかが満たされた場合にresultオブジェクトを更新します

---

**1. resultにitem.keyがまだ存在しない場合（つまり、そのキーの要素が初めて見つかった場合）**

**2.  item.dateがresult[item.key].dateより新しい場合（つまり、そのキーの要素で最新の日付が見つかった場合）**

**3. item.dateとresult[item.key].dateが同じで、かつitem.regiDateがresult[item.key].regiDateより新しい場合（つまり、そのキーの要素で日付が同じでも登録日が最新のものが見つかった場合）**

---

そしてJSに用意されたObject.values()メソッドを使い、resultのすべての値を配列に変換し、outputに格納します。

最初は『resultは配列でよくね？』と思っていましたが、

配列だと要素全体を検索する都合上、要素の数に比例して検索時間が増えるので、パフォーマンス的に厳しいかなと考えました。

一方で連想配列を使えば、プロパティの数に関係なく、特定のキーを持つプロパティに直接アクセスできます。


### 配列と連想配列（オブジェクト）のパフォーマンスの違い
この両者のパフォーマンスの違いについて、誤解を恐れずもう少し整理しておきます。

配列の場合、配列内の特定の要素を見つけるためには、最悪の場合、配列のすべての要素をチェックする必要があります。

例として先ほどのdata配列を見てみましょう。

```javascript
var data = [
  { key: 'A', date: '2023/05/01', regiDate: '2023/04/25' },
  { key: 'B', date: '2023/05/02', regiDate: '2023/04/26' },
  { key: 'C', date: '2023/05/03', regiDate: '2023/04/27' },
  { key: 'A', date: '2023/05/04', regiDate: '2023/04/28' },
  { key: 'D', date: '2023/05/05', regiDate: '2023/04/29' },
  { key: 'B', date: '2023/05/02', regiDate: '2023/04/30' },
  { key: 'E', date: '2023/05/07', regiDate: '2023/05/01' },
  { key: 'D', date: '2023/05/08', regiDate: '2023/05/02' },
  { key: 'C', date: '2023/05/09', regiDate: '2023/05/03' },
  { key: 'A', date: '2023/05/04', regiDate: '2023/05/04' }
];
```

条件に「そのキーの要素が初めて見つかった場合、更新する」というものがありました。

配列の場合、上記の配列からkeyが'E'のオブジェクトを見つけるためには、最初の要素から順に配列を走査していき、最後の要素（keyが'E'のオブジェクト）に到達するまでに時間がかかります。

---

```javascript
var data = [
  A: [
    { key: 'A', date: '2023/05/01', regiDate: '2023/04/25' },
    { key: 'A', date: '2023/05/04', regiDate: '2023/04/28' },
    { key: 'A', date: '2023/05/04', regiDate: '2023/05/04' }
  ],
  B: [
    { key: 'B', date: '2023/05/02', regiDate: '2023/04/26' },
    { key: 'B', date: '2023/05/02', regiDate: '2023/04/30' }
  ],
  C: [
    { key: 'C', date: '2023/05/03', regiDate: '2023/04/27' },
    { key: 'C', date: '2023/05/09', regiDate: '2023/05/03' }
  ],
  D: [
    { key: 'D', date: '2023/05/05', regiDate: '2023/04/29' },
    { key: 'D', date: '2023/05/08', regiDate: '2023/05/02' }
  ],
  E: [ { key: 'E', date: '2023/05/07', regiDate: '2023/05/01' } ]
];
```

一方、連想配列であれば最初から検索することなく、特定のキー（例えば'A'など）に直接アクセスできます。

この点で、要素の数が多くなるほど連想配列を使うメリットがあります。