JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptでオブジェクト配列を再帰的にツリー構造へ変換する方法

JavaScriptでは、parentchild の関係を持つフラットなオブジェクト配列を、階層的なツリー構造のJSONへ変換したいケースがよくあります。例えば、組織図、カテゴリーメニュー、ファイルシステムのようなデータを扱う場合などが該当します。

本記事では、再帰処理を使ってこうした配列をツリー構造に変換する実装方法を、サンプルコード付きでわかりやすく解説します。

元データとなるオブジェクト配列

まず、次のようなオブジェクトの配列があると仮定しましょう。

const arr = [
    {
        "parentIndex": '0' ,
        "childIndex": '3' ,
        "parent": "ROOT",
        "child": "root3"
    },
    {
        "parentIndex": '3' ,
        "childIndex": '2' ,
        "parent": "root3" ,
        "child": "root2"
    },
    {
        "parentIndex": '3' ,
        "childIndex": '1' ,
        "parent": "root3" ,
        "child": "root1"
    }
];

このデータでは、「ROOT」というルート要素の下に「root3」があり、さらにその下に「root2」と「root1」がぶら下がる親子関係が表現されています。

期待する出力(ツリー構造)

この配列から生成したいツリー構造は、以下のような形になります。

nodeStructure: {
    text: { name: "root3" },
    children: [
        {
            text: { name: "root2" }
        },
        {
            text: { name: "root1" }
        }
    ]
}
};

実装例

それでは、実際のコードを見てみましょう。処理の中核となるのは次の2つの関数です。

  • partial関数: 渡された条件に一致する要素だけを配列から抽出するヘルパー関数
  • findNodes関数: 指定された親キーに対応する子ノードを探し、さらにその子を再帰的に辿っていく本体関数
const arr = [
    {
        "parentIndex": '0' ,
        "childIndex": '3' ,
        "parent": "ROOT",
        "child": "root3"
    },
    {
        "parentIndex": '3' ,
        "childIndex": '2' ,
        "parent": "root3" ,
        "child": "root2"
    },
    {
        "parentIndex": '3' ,
        "childIndex": '1' ,
        "parent": "root3" ,
        "child": "root1"
    }
];
const partial = (arr = [], condition) => {
    const result = [];
    for (let i = 0; i < arr.length; i++) {
        if(condition(arr[i])){
            result.push(arr[i]);
        }
    }
    return result;
}
const findNodes = (parentKey,items) => {
    let subItems = partial(items, n => n.parent === parentKey);
    const result = [];
    for (let i = 0; i < subItems.length; i++) {
        let subItem = subItems[i];
        let resultItem = {
            text: {name:subItem.child}
        };
        let kids = findNodes(subItem.child , items);
        if(kids.length){
            resultItem.children = kids;
        }
        result.push(resultItem);
    }
    return result;
}
console.log(JSON.stringify(findNodes('ROOT', arr), undefined, 4));

実行結果

コンソールには、次のようにツリー構造化されたJSONが出力されます。

[
    {
        "text": {
            "name": "root3"
        },
        "children": [
            {
                "text": {
                    "name": "root2"
                }
            },
            {
                "text": {
                    "name": "root1"
                }
            }
        ]
    }
]

コードの仕組み

処理の流れを簡単に整理しておきましょう。

  1. findNodes('ROOT', arr) を呼び出すと、まず partial 関数によって parent === 'ROOT' を満たす要素(ここでは「root3」)が抽出されます。
  2. 抽出された各要素について、text.name に子の名前を持つノードオブジェクトを作成します。
  3. その子の名前を新しい親キーとして findNodes を再帰呼び出しすることで、さらに深い階層の子ノードが取得されます。
  4. 子ノードが存在する場合のみ children プロパティを設定するため、リーフノードには余計な空配列が付かず、クリーンなツリー構造になります。

このように再帰を活用すれば、どれほど階層が深いデータでも、フラットな配列から柔軟にツリー構造を組み立てることができます。配列の走査には filterreduce といった標準メソッドを使う書き方もありますので、用途に応じて実装を最適化してみてください。

  1. JavaScriptで配列をJSONに変換する方法|JSON.stringify()の使い方を解説

    JavaScriptで配列をJSON形式の文字列に変換するには、JSON.stringify()メソッドを使います。このメソッドは、配列やオブジェクトを引数として渡すだけで、JSON形式の文字列を簡単に生成できる非常に便利な機能です。 サンプルコード 以下は、ボタンをクリックすると配列がJSONに変換されて画面に表示されるシンプルなデモです。 <!DOCTYPE html> <html> <head> <style>    body {       font-family: "Segoe

  2. JavaScriptのlengthプロパティで配列オブジェクトの長さを取得する方法

    JavaScriptにおけるlengthプロパティとはJavaScriptのlengthプロパティは、文字列や配列などのオブジェクトが持つ要素数(サイズ)を返すために使用されます。配列の場合は格納されている要素の個数、文字列の場合は文字数を取得できます。ここでは、文字列と配列オブジェクトの長さをlengthプロパティで取得するサンプルコードを紹介します。サンプルコード以下の例では、ボタンをクリックすると配列の長さが画面に表示される仕組みを実装しています。<!DOCTYPE html> <html lang="ja"> <head> <