JavaScriptで同じidを持つ配列内のオブジェクトを1つにマージする方法
はじめに
JavaScriptを扱っていると、APIのレスポンスやデータ変換の過程で「同じidを持つデータが複数のオブジェクトに分かれている」という状況によく出会います。本記事では、このような配列をidごとにグループ化し、1つのオブジェクトへ統合(マージ)する方法を実例とともに解説します。
まず、例として次のようなオブジェクトの配列を用意しました。
const arr = [
{id: 1, h1: 'Daily tests'},
{id: 2, h1: 'Details'},
{id: 1, h2: 'Daily classes'},
{id: 3, h2: 'Results'},
{id: 2, h3: 'Admissions'},
{id: 1, h4: 'Students'},
{id: 2, h5: 'Alumni'},
{id: 3, h3: 'Appreciations'},
{id: 1, h5: 'Tiny Tots'},
{id: 1, h6: 'Extras'},
];この配列に対して、同じidを持つ見出しプロパティ(h1、h2、h3…)をすべて1つのオブジェクトにまとめる関数を作成します。期待する結果は、id: 1の要素6件、id: 2の要素3件、id: 3の要素2件がそれぞれ結合された、3つのオブジェクトからなる配列です。
実装例:reduce()とfindIndex()を使う方法
ここでは、Array.prototype.reduce()メソッドを活用します。処理の流れは以下の通りです。
- 初期値として空の配列を用意する
- 各要素について、findIndex()で「同じidを持つオブジェクトが既に蓄積配列に存在するか」を確認する
- 存在すればObject.keys(val)[1]で見出しのキー名(h1など)を取得し、既存オブジェクトにそのプロパティを追加する
- 存在しなければ、その要素をそのまま蓄積配列に追加する
const arr = [
{id: 1, h1: 'Daily tests'},
{id: 2, h1: 'Details'},
{id: 1, h2: 'Daily classes'},
{id: 3, h2: 'Results'},
{id: 2, h3: 'Admissions'},
{id: 1, h4: 'Students'},
{id: 2, h5: 'Alumni'},
{id: 3, h3: 'Appreciations'},
{id: 1, h5: 'Tiny Tots'},
{id: 1, h6: 'Extras'},
];
const clubArray = (arr) => {
return arr.reduce((acc, val, ind) => {
const index = acc.findIndex(el => el.id === val.id);
if(index !== -1){
const key = Object.keys(val)[1];
acc[index][key] = val[key];
} else {
acc.push(val);
}
return acc;
}, []);
};
console.log(clubArray(arr));ポイント解説
Object.keys(val)[1]は、オブジェクトの2番目のキー(idの直後に定義されている見出しキー)を取得しています。この例のように各オブジェクトが必ずid+見出し1つの構成であれば有効ですが、キーの順序が保証されないケースでは注意が必要です。
また、この方法は要素ごとにfindIndex()で線形探索を行うため、計算量はO(n²)になります。小規模なデータでは問題ありませんが、大量のデータを扱う場合は後述のMapを使った方法がおすすめです。
より高速な代替手法:Mapを使うO(n)アプローチ
パフォーマンスを重視する場合は、Mapを使ってidとオブジェクトの対応を管理すると、全体を1回のループで処理できます。
const clubArrayFast = (arr) => {
const map = new Map();
for (const obj of arr) {
const [key, value] = Object.entries(obj);
if (map.has(obj.id)) {
map.get(obj.id)[key] = value;
} else {
map.set(obj.id, {...obj});
}
}
return [...map.values()];
};このアプローチでは検索が不要になるため、データ件数が増えても安定した速度を保てます。また、Mapは挿入順序を保持するため、元の配列での出現順も維持される点もメリットです。
出力結果
いずれの方法でも、コンソールには次のような結果が出力されます。
[
{
id: 1,
h1: 'Daily tests',
h2: 'Daily classes',
h4: 'Students',
h5: 'Tiny Tots',
h6: 'Extras'
},
{ id: 2, h1: 'Details', h3: 'Admissions', h5: 'Alumni' },
{ id: 3, h2: 'Results', h3: 'Appreciations' }
]まとめ
同じキー(id)を持つ配列内のオブジェクトをマージするには、reduce()とfindIndex()を組み合わせる方法がシンプルで分かりやすい選択肢です。一方で、データ量が多い場合はMapを使ったO(n)の実装の方が効率的です。用途やデータ規模に応じて使い分けるとよいでしょう。
-
【JavaScript入門】複数のオブジェクトを1つにマージして単一のオブジェクト配列を作成する方法
JavaScriptでは、Object.assign()メソッドとスプレッド構文(...)を組み合わせることで、配列内の複数のオブジェクトを1つのオブジェクトに簡単にマージすることができます。 Object.assign()は、1つ以上のコピー元オブジェクトから、コピー先のオブジェクトへすべてのプロパティをコピーするためのメソッドです。スプレッド構文を使って配列の要素を展開することで、各オブジェクトのキーと値が1つのオブジェクトに統合されます。 コード例 以下のコードは、配列内の複数のオブジェクトを単一のオブジェクトにマージする例です。 <!DOCTYPE html> <ht
-
JavaScriptでnull・空のオブジェクトを含む配列に値を割り当てる方法
JavaScriptでは、forEach()メソッドとObject.keys()メソッドを組み合わせることで、nullや空のオブジェクトを含む配列に対して効率的に値を割り当てることができます。本記事では、実際のコード例を交えながら、その具体的な実装方法をわかりやすく解説します。 サンプルコード 以下は、JavaScriptを使用してnull/空のオブジェクトを持つ配列に値を割り当てるコード例です。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&qu