はじめに
JavaScriptの連想配列を加工してみようと思い、いろいろ試してみました。
そこで連想配列か配列か、どちらを使えば効率的に課題をクリアできるか考えたので、その過程をまとめます。
環境
Node.js(v20.11.0)
問題
- 次のような連想配列がある
[
{ 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プログラムを作成。
【条件】
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配列を見てみましょう。
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'のオブジェクト)に到達するまでに時間がかかります。
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'など)に直接アクセスできます。
この点で、要素の数が多くなるほど連想配列を使うメリットがあります。