Open In App

Build Tree Array from Flat Array in JavaScript

Last Updated : 01 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

To convert a flat array of comments into a tree-like structure using JavaScript. This technique is particularly useful when you need to render nested comments or any other hierarchical data in your web application. We will write a function called buildCommentsTree that takes the flat array of comments as input and returns a tree-like array of comments.

Below are the approaches to build a tree array from a flat array in javascript:

Using a Loop and Object References

This approach involves creating a map or a reference object to store all the nodes. We loop through the flat array and create the tree array by linking the child nodes to their parent nodes using the reference object. It utilizes a “nodeMap” to efficiently store and retrieve comments by their IDs, initializing each comment with an empty “children” array. By iterating over the flat array twice, it constructs the tree array, linking comments to their respective parent comments.

Example: Implementation of Building a tree array from a flat array in JavaScript Using a Loop and Object References.

JavaScript
const flatComments = [
    { id: 1, parentId: null, author: 'Jeetu', 
        content: 'This is a great article!' },
    { id: 2, parentId: 1, author: 'Mihika', 
        content: 'I agree, very informative.' },
    { id: 3, parentId: 2, author: 'Disha', 
        content: 'I added more Examples in this article' },
    { id: 4, parentId: null, author: 'Shravan', 
        content: 'Great, Thanks!!' },
];

function buildTreeArray(flatArray) {
    
    // Store references to nodes by their IDs
    const nodeMap = {};
    
    // Store the root nodes of the tree
    const result = [];

    // Create a reference object
    flatArray.forEach(item => {
        nodeMap[item.id] = { ...item, children: [] };
    });

    // Build the tree array
    flatArray.forEach(item => {
        const node = nodeMap[item.id];
        if (item.parentId !== null) {
            nodeMap[item.parentId].children.push(node);
        } else {
            result.push(node);
        }
    });

    return result;
}

const commentsTree = buildTreeArray(flatComments);
console.log(JSON.stringify(commentsTree, null, 2));

Output:

[
{
"id": 1,
"parentId": null,
"author": "Jeetu",
"content": "This is a great article!",
"children": [
{
"id": 2,
"parentId": 1,
"author": "Mihika",
"content": "I agree, very informative.",
"children": [
{
"id": 3,
"parentId": 2,
"author": "Disha",
"content": "I added more Examples in this article",
"children": []
}
]
}
]
},
{
"id": 4,
"parentId": null,
"author": "Shravan",
"content": "Great, Thanks!!",
"children": []
}
]

Using Array.prototype.reduce()

This approach uses the reduce method to iterate over the flat array the code transforms a flat array of comments into a tree-like structure, where each comment may have child comments. It employs a node map to efficiently store and access comments by their IDs, utilizing the ‘reduce’ function to build the map. The resulting tree array represents the hierarchy of comments, with root nodes stored in the ‘result’ array and children nested within their respective parents.

Example: Implementation of Building a tree array from a flat array in JavaScript Using Array.prototype.reduce().

JavaScript
const flatComments = [
    { id: 1, parentId: null, author: 'Jeetu',
        content: 'This is a great article!' },
    { id: 2, parentId: 1, author: 'Mihika',
        content: 'I agree, very informative.' },
    { id: 3, parentId: 2, author: 'Disha',
        content: 'I added more Examples in this article' },
    { id: 4, parentId: null, author: 'Shravan',
        content: 'Great, Thanks!!' },
];

function buildTreeArray(flatArray) {
    // Store the root nodes of the tree
    
    const result = [];
    
    // Use reduce to create a nodeMap
    const nodeMap = flatArray.reduce((acc, item) => {
        acc[item.id] = { ...item, children: [] };
        return acc;
    }, {});

    // Iterate through flatArray to build the tree
    flatArray.forEach(item => {
        if (item.parentId === null) {
            result.push(nodeMap[item.id]);
        } else {
            nodeMap[item.parentId].children
                                  .push(nodeMap[item.id]);
        }
    });

    return result;
}

const commentsTree = buildTreeArray(flatComments);
console.log(JSON.stringify(commentsTree, null, 2));

Output:

[
{
"id": 1,
"parentId": null,
"author": "Jeetu",
"content": "This is a great article!",
"children": [
{
"id": 2,
"parentId": 1,
"author": "Mihika",
"content": "I agree, very informative.",
"children": [
{
"id": 3,
"parentId": 2,
"author": "Disha",
"content": "I added more Examples in this article",
"children": []
}
]
}
]
},
{
"id": 4,
"parentId": null,
"author": "Shravan",
"content": "Great, Thanks!!",
"children": []
}
]

Using Recursion

This approach involves creating a recursive function that constructs the tree array by recursively building the child nodes for each parent node. Finally, it filters the flat array for root nodes and maps each root node to its corresponding tree structure, resulting in a nested tree array.

Example: Implementation of Building a tree array from a flat array in JavaScript Using Recursion.

JavaScript
const flatComments = [
    { id: 1, parentId: null, author: 'Jeetu',
        content: 'This is a great article!' },
    { id: 2, parentId: 1, author: 'Mihika', 
        content: 'I agree, very informative.' },
    { id: 3, parentId: 2, author: 'Disha', 
        content: 'I added more Examples in this article' },
    { id: 4, parentId: null, author: 'Shravan',
        content: 'Great, Thanks!!' },
];

function buildTreeArray(flatArray) {
    
    // Use reduce to create a nodeMap
    const nodeMap = flatArray.reduce((acc, item) => {
        acc[item.id] = { ...item, children: [] };
        return acc;
    }, {});

    // Recursive function to build nodes
    const buildNode = id => {
        const node = nodeMap[id];
        if (!node) return null;

        // Filter flatArray for items with parentId === id
        node.children = flatArray
            .filter(item => item.parentId === id)
            .map(item => buildNode(item.id));

        return node;
    };

    // Filter flatArray for root nodes
    return flatArray.filter(item => item.parentId === null)
                    .map(item => buildNode(item.id));
}

const commentsTree = buildTreeArray(flatComments);
console.log(JSON.stringify(commentsTree, null, 2));

Output:

[
{
"id": 1,
"parentId": null,
"author": "Jeetu",
"content": "This is a great article!",
"children": [
{
"id": 2,
"parentId": 1,
"author": "Mihika",
"content": "I agree, very informative.",
"children": [
{
"id": 3,
"parentId": 2,
"author": "Disha",
"content": "I added more Examples in this article",
"children": []
}
]
}
]
},
{
"id": 4,
"parentId": null,
"author": "Shravan",
"content": "Great, Thanks!!",
"children": []
}
]

Practical Example of Building tree array from a flat array in JavaScript

This example uses a Loop and Object References to build a tree view of comments from the “flatComments” array data and then render it in web view using the renderCommentsTree() function which interacts with HTML Code. Use CSS for a better look.

Example: Practical Example of Building a tree array from a flat array in JavaScript.

HTML
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" 
          content="width=device-width, initial-scale=1.0">
    <title>Comments Tree</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <h3>Practical Example of Building tree
          array from flat array in JavaScript
      </h3>
    <div id="comments-container"></div>
    <script src="script.js"></script>
</body>

</html>
CSS
/* style.css*/

body {
    font-family: Arial, sans-serif;
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
    background-color: #f2f2f2;
    color: #333;
}

h3 {
    text-align: center;
    color: #2c6e49;
}

.comment {
    border: 1px solid #c5d6c7;
    border-radius: 4px;
    padding: 10px;
    margin-bottom: 10px;
    background-color: #e8f5e9;
}

.comment-author {
    font-weight: bold;
    margin-bottom: 5px;
    color: #2c6e49;
}

.comment-content {
    margin-bottom: 10px;
}

.replies {
    margin-left: 20px;
}
JavaScript
// script.js

// Flat array of comments
const flatComments = [
    { id: 1, parentId: null, author: 'Jeetu',
      content: 'This is a great article!' },
    { id: 2, parentId: 1, author: 'Mihika', 
      content: 'I agree, very informative.' },
    { id: 3, parentId: 1, author: 'Disha', 
      content: 'I was wondering if you could provide more examples on the topic?' },
    { id: 4, parentId: 3, author: 'Shravan', 
      content: 'Ohhk!!' },
    { id: 6, parentId: 4, author: 'Shravan', 
      content: 'I added more Examples!!' },
    { id: 7, parentId: 6, author: 'Disha', 
      content: 'Great, thanks!' }
];

// Build the tree array
function buildCommentsTree(flatComments) {
    const nodeMap = {};
    const result = [];

    // Create a reference object
    flatComments.forEach(comment => {
        nodeMap[comment.id] = 
            { ...comment, children: [] };
    });

    // Build the tree array
    flatComments.forEach(comment => {
        const node = nodeMap[comment.id];
        if (comment.parentId !== null) {
            nodeMap[comment.parentId]
                           .children.push(node);
        } else {
            result.push(node);
        }
    });

    return result;
}

const commentsTree = buildCommentsTree(flatComments);

// Render the comments tree in the webview
function renderCommentsTree(commentsTree) {
    const commentsContainer = 
            document.getElementById('comments-container');

    function renderComment(comment, level = 0) {
        const commentElement = 
                        document.createElement('div');
        commentElement.classList.add('comment');
        commentElement.style.marginLeft = `${level * 20}px`;
        commentElement.innerHTML = `
            <div class="comment-author">${comment.author}</div>
            <div class="comment-content">${comment.content}</div>
            <div class="replies"></div>`;

        const repliesContainer = 
                commentElement.querySelector('.replies');
        comment.children.forEach(child => {
            repliesContainer
                .appendChild(renderComment(child, level + 1));
        });

        return commentElement;
    }

    commentsTree.forEach(comment => {
        commentsContainer.appendChild(renderComment(comment));
    });
}

renderCommentsTree(commentsTree);

Output:

movep121

Output



Like Article
Suggest improvement
Share your thoughts in the comments