JavaScriptで親キーをもとに子キー(子孫ID一覧)を生成する方法を解説
Webアプリケーションの開発では、カテゴリやフォルダ階層のように親子関係を持つデータを扱う機会が多くあります。本記事では、parent_id を持つオブジェクトの配列から、各要素に「直接・間接の子孫すべてのID」をまとめた childs プロパティを付与する方法を解説します。
元データの確認
まず、今回使用するサンプルデータです。各オブジェクトは id、parent_id、title の3つのプロパティを持ち、parent_id が 0 のものは最上位(親を持たない)要素を表します。
const arr = [
{ id: 1, parent_id: 0, title: 'Movies' },
{ id: 2, parent_id: 0, title: 'Music' },
{ id: 3, parent_id: 1, title: 'Russian movies' },
{ id: 4, parent_id: 2, title: 'Russian music' },
{ id: 5, parent_id: 3, title: 'New' },
{ id: 6, parent_id: 3, title: 'Top10' },
{ id: 7, parent_id: 4, title: 'New' },
{ id: 8, parent_id: 4, title: 'Top10' },
{ id: 9, parent_id: 0, title: 'Soft' }
];
目標とする出力
作成する関数は、この配列を受け取り、各オブジェクトに childs という追加プロパティを持つ新しい配列を返します。childs には、そのオブジェクトの直接の子だけでなく、孫以降の間接的な子孫もすべて含めたIDリストが格納されます。
例えば、id が 1 の「Movies」の場合、直接の子である 3(Russian movies)に加え、3 の子である 5 と 6 も対象となるため、childs: [3, 5, 6] になります。一方、子を持たない id 9 の「Soft」は空配列です。
[
{ id: 1, parent_id: 0, title: 'Movies', childs: [ 3, 5, 6 ] },
{ id: 2, parent_id: 0, title: 'Music', childs: [ 4, 7, 8 ] },
{ id: 3, parent_id: 1, title: 'Russian movies', childs: [ 5, 6 ] },
{ id: 4, parent_id: 2, title: 'Russian music', childs: [ 7, 8 ] },
{ id: 5, parent_id: 3, title: 'New', childs: [] },
{ id: 6, parent_id: 3, title: 'Top10', childs: [] },
{ id: 7, parent_id: 4, title: 'New', childs: [] },
{ id: 8, parent_id: 4, title: 'Top10', childs: [] },
{ id: 9, parent_id: 0, title: 'Soft', childs: [] }
]
実装コード
Array.prototype.reduce() を使うと、次のように簡潔に実装できます。
const arr = [
{ id: 1, parent_id: 0, title: 'Movies' },
{ id: 2, parent_id: 0, title: 'Music' },
{ id: 3, parent_id: 1, title: 'Russian movies' },
{ id: 4, parent_id: 2, title: 'Russian music' },
{ id: 5, parent_id: 3, title: 'New' },
{ id: 6, parent_id: 3, title: 'Top10' },
{ id: 7, parent_id: 4, title: 'New' },
{ id: 8, parent_id: 4, title: 'Top10' },
{ id: 9, parent_id: 0, title: 'Soft' }
];
const generateChild = arr => {
return arr.reduce((acc, val, ind, array) => {
const childs = [];
array.forEach((el, i) => {
if(childs.includes(el.parent_id) || el.parent_id === val.id){
childs.push(el.id);
};
});
return acc.concat({...val, childs});
}, []);
};
console.log(generateChild(arr));
コードの仕組み
- reduce()による蓄積処理: 配列の各要素を順番に処理し、
childsを追加した新しいオブジェクトを初期値[]に連結していきます。 - 直接の子の判定:
el.parent_id === val.idにより、現在処理中の要素を親に持つオブジェクトを検出します。 - 間接の子の判定:
childs.includes(el.parent_id)により、すでに収集した子を親に持つ要素(孫以降)も順次リストへ追加します。 - スプレッド構文 {...val, childs}: 元のオブジェクトのプロパティを保持したまま、
childsプロパティのみを追加します。
注意点: このアルゴリズムは、配列内で親要素が必ず子要素より先に現れることを前提としています。並び順が保証されないデータを扱う場合は、事前に階層順へソートするか、Map を使った再帰的な実装に置き換えるのが安全です。また、計算量は O(n²) となるため、大規模データでは Map を活用した O(n) の手法を検討するとよいでしょう。
実行結果
コンソールには次のように出力されます。
[
{ id: 1, parent_id: 0, title: 'Movies', childs: [ 3, 5, 6 ] },
{ id: 2, parent_id: 0, title: 'Music', childs: [ 4, 7, 8 ] },
{ id: 3, parent_id: 1, title: 'Russian movies', childs: [ 5, 6 ] },
{ id: 4, parent_id: 2, title: 'Russian music', childs: [ 7, 8 ] },
{ id: 5, parent_id: 3, title: 'New', childs: [] },
{ id: 6, parent_id: 3, title: 'Top10', childs: [] },
{ id: 7, parent_id: 4, title: 'New', childs: [] },
{ id: 8, parent_id: 4, title: 'Top10', childs: [] },
{ id: 9, parent_id: 0, title: 'Soft', childs: [] }
]
まとめ
reduce と forEach を組み合わせることで、フラットな親子関係データから各要素の子孫ID一覧を簡単に生成できました。ツリー構造の構築やパンくずリストの生成など、階層データを扱うさまざまな処理の基礎となるテクニックなので、ぜひマスターしておきましょう。
-
JavaScriptでハッシュのキーを取得するには?Object.keys()メソッドの使い方
JavaScriptでは、ハッシュは一般的にオブジェクトとして表現されます。オブジェクトが持つすべてのキー(プロパティ名)を取得したい場合、最も簡単で推奨される方法がObject.keys()メソッドです。このメソッドは、指定したオブジェクトの列挙可能なプロパティ名を文字列の配列として返します。 基本構文 Object.keys(オブジェクト名) 戻り値はキー名の配列になるため、そのまま配列操作メソッド(forEachやmapなど)と組み合わせて使えるのも大きな利点です。 サンプルコード 以下は、ボタンをクリックするとハッシュ(オブジェクト)のキーを画面に表示する例です。 <!DOCTY
-
JavaScriptで親要素の子要素を取得する方法【サンプルコード付き】
JavaScriptでは、親要素が持つchildrenプロパティを参照することで、その直下にある子要素をまとめて取得できます。本記事では、実際に動作するサンプルコードを使いながら、具体的な手順をわかりやすく解説します。 サンプルコード 以下は、JavaScriptを使って親要素(parent1)の子要素を取得し、ボタンのクリックで一括表示させる例です。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta nam