【JavaScript】一意のキー(roll番号)を使ってオブジェクトのプロパティをマージする方法
本記事では、names と marks という2つのプロパティを持つ students オブジェクトを例に、共通する一意のキーを手がかりにデータを統合する方法を解説します。
問題の概要
students オブジェクトは以下のような構造になっています。names は各要素が name と roll プロパティを持つオブジェクトの配列、marks は各要素が mark と roll プロパティを持つオブジェクトの配列です。
今回のタスクは、各オブジェクトが共通して持つ roll プロパティ(出席番号)を照合し、marks と names の情報を1つにまとめることです。
const students = {
marks: [{
roll: 123,
mark: 89
}, {
roll: 143,
mark: 69
}, {
roll: 126,
mark: 91
}, {
roll: 112,
mark: 80
}],
names: [{
name: 'Aashish',
roll: 126
}, {
name: 'Sourav',
roll: 112
}, {
name: 'Vineet',
roll: 143
}, {
name: 'Kartik',
roll: 123
}]
}
combineProperties 関数の実装
次に、students オブジェクトを受け取り、追加のメモリ領域を使わずにその場(in-place)でプロパティを統合する関数 combineProperties を定義します。処理の流れは以下の通りです。
marks配列をforEachで走査する- 各要素の
rollをもとに、names配列から一致するオブジェクトをfind()で検索する - 見つかった
nameをmarks側のオブジェクトに新しいプロパティとして追加する - 最後に不要になった
namesプロパティを削除する
const combineProperties = (students) => {
const { marks, names } = students;
marks.forEach(marksObj => {
const { roll } = marksObj;
marksObj.name = names.find(namesObj => namesObj.roll ===roll).name;
})
delete students['names'];
};
combineProperties(students);
console.log(students);
このコードの時間計算量は O(mn) です(m と n はそれぞれ names 配列と marks 配列のサイズ)。空間計算量は O(1) ですが、marks 配列の各要素に新しい name プロパティが追加される点には注意が必要です。
完全なサンプルコード
const students = {
marks: [{
roll: 123,
mark: 89
}, {
roll: 143,
mark: 69
}, {
roll: 126,
mark: 91
}, {
roll: 112,
mark: 80
}],
names: [{
name: 'Aashish',
roll: 126
}, {
name: 'Sourav',
roll: 112
}, {
name: 'Vineet',
roll: 143
}, {
name: 'Kartik',
roll: 123
}]
}
const combineProperties = (students) => {
const { marks, names } = students;
marks.forEach(marksObj => {
const { roll } = marksObj;
marksObj.name = names.find(namesObj => namesObj.roll ===roll).name;
})
delete students['names'];
};
combineProperties(students);
console.log(students);
実行結果
コンソールへの出力は以下のようになります。各 marks の要素に、対応する roll 番号を持つ生徒の名前が結合されていることが確認できます。
{
marks: [
{ roll: 123, mark: 89, name: 'Kartik' },{ roll: 143, mark: 69, name: 'Vineet' },
{ roll: 126, mark: 91, name: 'Aashish' },{ roll: 112, mark: 80, name: 'Sourav' }
]
}
応用:Map を使って高速化する
上記の実装は find() を使用しているため、データ件数が増えると計算量 O(m × n) がボトルネックになります。大規模なデータを扱う場合は、あらかじめ names を roll をキーとした Map に変換しておくことで、時間計算量を O(m + n) まで改善できます。
const combinePropertiesOptimized = (students) => {
const { marks, names } = students;
const nameMap = new Map(names.map(n => [n.roll, n.name]));
marks.forEach(obj => {
obj.name = nameMap.get(obj.roll);
});
delete students['names'];
};
このように、一意のキーをもとにオブジェクト配列をマージする処理は、API レスポンスの整形やデータ集計など、実務でも頻繁に登場するパターンです。データ規模に応じて find() と Map を使い分けるとよいでしょう。
-
JavaScriptで別のオブジェクトを介してオブジェクトにアクセスする方法
JavaScriptでは、あるオブジェクトを定義する際に、別のオブジェクトのプロパティやメソッドを参照することで、その値を取得したり、メソッドの実行結果を利用したりすることができます。この記事では、既存のオブジェクト(obj)を介して、新しいオブジェクト(obj2)からプロパティやメソッドにアクセスする方法を、具体的なコード例とともに解説します。押さえておきたいポイントオブジェクトリテラルの中で obj.lastName のように記述すると、その時点での値が新しいオブジェクトにコピーされます。obj.welcome() のようにメソッド名の後に括弧を付けると、オブジェクト定義時にメソッドが即座
-
【JavaScript入門】Symbolを使ってオブジェクトごとに一意のIDを作成する方法
はじめにJavaScriptでオブジェクトごとに一意のIDを作成したい場合、Symbol()を使うのが最も簡単かつ確実な方法です。Symbolは呼び出されるたびに必ず新しい一意の値を生成するため、たとえ同じ説明文字列を渡しても、二度と同じ値にはなりません。以下は、各オブジェクトに対して一意のIDを作成するサンプルコードです。実装例<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewp