preface

Tree-structured data manipulation is an essential skill for a developer. In the actual business development, we will also encounter many tree structures, such as the most common regional tree, as well as enterprise structure tree, school level organization tree and so on.

Below sorted out a series of JavaScript tree operation methods, combined with examples, I believe that we in the actual development work or more or less will use.

Array flattening

The sample

const arr = [1[2[3.4]], 5[6]].Copy the code

methods

1, the recursion

const flatten = (arr) = > {
    let res = [];
    arr.map(item= > {
        if(Array.isArray(item)) {
            res = res.concat(flatten(item));
        } else{ res.push(item); }});return res;
}
Copy the code

2, reduce

const flatten = (arr) = > {
    return arr.reduce((result, item) = > {
        return result.concat(Array.isArray(item) ? flatten(item) : item); } []); }Copy the code

3, flat

const flatten = (arr) = > {
    return arr.flat(Infinity)}Copy the code

The results

const result = flatten(arr);
console.log(result);

// Run the result
[1.2.3.4.5.6]
Copy the code

Array to tree structure

The sample

const arr = [
    {
        name: 'Ming'.id: 1.pid: 0}, {name: 'flower'.id: 11.pid: 1}, {name: 'xiaohua'.id: 111.pid: 11}, {name: 'xiao li'.id: 112.pid: 11}, {name: 'little red'.id: 12.pid: 1}, {name: 'wang'.id: 2.pid: 0}, {name: 'xiao Lin'.id: 21.pid: 2}, {name: 'xiao li'.id: 22.pid: 2,}]Copy the code

methods

1. Non-recursion

 const arrayToTree = (arr) = > {
    let result = [];
    if (!Array.isArray(arr) || arr.length === 0) {
        return result
    }
    let map = {};
    arr.forEach(item= > map[item.id] = item);
    arr.forEach(item= > {
        const parent = map[item.pid];
        if(parent){
            (parent.children || (parent.children=[])).push(item);
        } else{ result.push(item); }})return result
}
Copy the code

2, the recursion

const arrayToTree = (arr, pid) = > {
    let res = [];
    arr.forEach(item= > {
        if(item.pid === pid){
            let itemChildren = arrayToTree(arr,item.id);
            if(itemChildren.length) { item.children = itemChildren; } res.push(item); }});return res;
}
Copy the code

The results

// const result = arrayToTree(arr);
const result = arrayToTree(arr, 0);
console.log(result);

// Run the result[{"name": "Xiao Ming"."id": 1."pid": 0."children": [{"name": "Flower"."id": 11."pid": 1."children": [{"name": "Wah"."id": 111."pid": 11
                    },
                    {
                        "name": "Xiao li"."id": 112."pid": 11}]}, {"name": "Little red"."id": 12."pid": 1}]}, {"name": "Wang"."id": 2."pid": 0."children": [{"name": "Lin"."id": 21."pid": 2
            },
            {
                "name": "Xiao li"."id": 22."pid": 2}}]]Copy the code

Tree structure transform array (flattened)

The sample

const tree = [
    {
        name: 'Ming'.id: 1.pid: 0.children: [{name: 'flower'.id: 11.pid: 1.children: [{name: 'xiaohua'.id: 111.pid: 11}, {name: 'xiao li'.id: 112.pid: 11,}]}, {name: 'little red'.id: 12.pid: 1,}]}, {name: 'wang'.id: 2.pid: 0.children: [{name: 'xiao Lin'.id: 21.pid: 2}, {name: 'xiao li'.id: 22.pid: 2,}]}]Copy the code

methods

1. Depth-first traversal

const treeToArray = (tree) = > {
    let stack = tree,
        result = [];
    while(stack.length ! = =0) {let pop = stack.pop();
        result.push({
            id: pop.id,
            name: pop.name,
            pid: pop.pid
        })
        let children = pop.children
        if(children){
            for(let i = children.length-1; i >=0; i--){
                stack.push(children[i])
            }
        }
    }
    return result
}
Copy the code

Breadth-first traversal

const treeToArray = (tree) = > {
    let queue = tree,
        result = [];
    while(queue.length ! = =0) {let shift = queue.shift();
        result.push({
            id: shift.id,
            name: shift.name,
            pid: shift.pid
        })
        let children = shift.children
        if(children){
            for(let i = 0; i < children.length; i++){
                queue.push(children[i])
            }
        }
    }
    return result
}
Copy the code

3. Do not consider attributes other than children

const treeToArray = (source) = >{
    let res = []
    source.forEach(item= >{ res.push(item) item.children && res.push(... treeToArray(item.children)) })return res.map((item) = > {
        if (item.children) {
            delete item.children
        }
        return item
    })
}
Copy the code

The results

const result = treeToArray(tree);
console.log(result);

// Run the result[{"name": "Xiao Ming"."id": 1."pid": 0
    },
    {
        "name": "Flower"."id": 11."pid": 1
    },
    {
        "name": "Wah"."id": 111."pid": 11
    },
    {
        "name": "Xiao li"."id": 112."pid": 11
    },
    {
        "name": "Little red"."id": 12."pid": 1
    },
    {
        "name": "Wang"."id": 2."pid": 0
    },
    {
        "name": "Lin"."id": 21."pid": 2
    },
    {
        "name": "Xiao li"."id": 22."pid": 2}]Copy the code

Tree filtering, reserving the data that meets the criteria and returning the tree structure

The sample

const tree = [
    {
        name: 'Ming'.id: 1.pid: 0.show: true.children: [{name: 'flower'.id: 11.pid: 1.show: true.children: [{name: 'xiaohua'.id: 111.pid: 11}, {name: 'xiao li'.id: 112.pid: 11.show: true,}]}, {name: 'little red'.id: 12.pid: 1,}]}, {name: 'wang'.id: 2.pid: 0.show: true.children: [{name: 'xiao Lin'.id: 21.pid: 2}, {name: 'xiao li'.id: 22.pid: 2,}]}]Copy the code

methods

Filter data from show to true

const filterTreeByFunc = (tree, func) = > {
    if (!Array.isArray(tree) || tree.length === 0) {
        return[]}return tree.filter(item= > {
        item.children = item.children && filterTreeByFunc(item.children, func)
        return func(item) || (item.children && item.children.length)
    })
}

const func = (item) = > {
    return item.show === true
}
Copy the code

The results

const result = filterTreeByFunc(tree, func);
console.log(result);

// Run the result[{"name": "Xiao Ming"."id": 1."pid": 0."show": true."children": [{"name": "Flower"."id": 11."pid": 1."show": true."children": [{"name": "Xiao li"."id": 112."pid": 11."show": true}}]}, {"name": "Wang"."id": 2."pid": 0."show": true."children": []}]Copy the code

Find the path of a node in the tree

The sample

const tree = [
    {
        name: 'Ming'.id: 1.pid: 0.children: [{name: 'flower'.id: 11.pid: 1.children: [{name: 'xiaohua'.id: 111.pid: 11}, {name: 'xiao li'.id: 112.pid: 11,}]}, {name: 'little red'.id: 12.pid: 1,}]}, {name: 'wang'.id: 2.pid: 0.children: [{name: 'xiao Lin'.id: 21.pid: 2}, {name: 'xiao li'.id: 22.pid: 2,}]}]Copy the code

methods

const getNodePath = (tree, id) = > {
    if (!Array.isArray(tree) || tree.length === 0) {
        return[]}const path = []
    const treeFindPath = (tree, id, path) = > {
        for (const item of tree) {
            path.push(item.id);
            if (item.id === id) {
                return path
            }
            if (item.children) {
                const findChildren = treeFindPath(item.children,id, path);
                if (findChildren.length) {
                    return findChildren;
                }
            }
            path.pop();
        }
        return [];
    }
    return treeFindPath(tree, id, path)
}
Copy the code

The results

const result = getNodePath(tree, 112);
console.log(result);

// Run the result
[1.11.112]
Copy the code

Fuzzy query tree

The sample

const tree = [
    {
        name: 'Xiao Ming Front End Expert'.id: 1.pid: 0.children: [{name: 'Little Front End programmer'.id: 11.pid: 1.children: [{name: 'Xiaohua Water Paddler'.id: 111.pid: 11}, {name: 'Xiao Li Fishing athlete'.id: 112.pid: 11,}]}, {name: 'Little Red Touch Fish Programmer'.id: 12.pid: 1,}]}, {name: 'The King inside the King'.id: 2.pid: 0.children: [{name: 'The King of Fish in Kobayashi'.id: 21.pid: 2}, {name: 'Lee Backend Programmer'.id: 22.pid: 2,}]}]Copy the code

methods

const fuzzyQueryTree = (arr, value) = > {
    if (!Array.isArray(arr) || arr.length === 0) {
        return[]}let result = [];
    arr.forEach(item= > {
        if (item.name.indexOf(value) > -1) {
            const children = fuzzyQueryTree(item.children, value);
            constobj = { ... item, children } result.push(obj); }else {
            if (item.children && item.children.length > 0) {
                const children = fuzzyQueryTree(item.children, value);
                constobj = { ... item, children }if (children && children.length > 0) { result.push(obj); }}}});return result;
};
Copy the code

The results

const result = fuzzyQueryTree(tree,'process');
console.log(result);

// Run the result[{"name": "Xiao Ming front End Expert"."id": 1."pid": 0."children": [{"name": "Little Front end programmer."."id": 11."pid": 1."children": []}, {"name": "Little Red Fish Programmer."."id": 12."pid": 1."children": []}]}, {"name": "The King inside the King."."id": 2."pid": 0."children": [{"name": "Xiao Li Backend Programmer"."id": 22."pid": 2."children": []}]}]Copy the code

Add attributes to the tree node

The sample

const tree = [
    {
        name: 'Ming'.id: 1.pid: 0.children: [{name: 'flower'.id: 11.pid: 1.children: [{name: 'xiaohua'.id: 111.pid: 11}, {name: 'xiao li'.id: 112.pid: 11,}]}, {name: 'little red'.id: 12.pid: 1,}]}, {name: 'wang'.id: 2.pid: 0.children: [{name: 'xiao Lin'.id: 21.pid: 2}, {name: 'xiao li'.id: 22.pid: 2,}]}]Copy the code

methods

const addAttrToNodes = (tree) = > {
    tree.forEach((item) = > {
        item.title = 'New generation of migrant workers'
        if (item.children && item.children.length > 0) {
            addAttrToNodes(item.children)
        }
    })
    return tree
}
Copy the code

The results

const result = addAttrToNodes(tree);
console.log(result);

// Run the result[{"name": "Xiao Ming"."id": 1."pid": 0."children": [{"name": "Flower"."id": 11."pid": 1."children": [{"name": "Wah"."id": 111."pid": 11."title": The "New generation of migrant workers"
                    },
                    {
                        "name": "Xiao li"."id": 112."pid": 11."title": The "New generation of migrant workers"}]."title": The "New generation of migrant workers"
            },
            {
                "name": "Little red"."id": 12."pid": 1."title": The "New generation of migrant workers"}]."title": The "New generation of migrant workers"
    },
    {
        "name": "Wang"."id": 2."pid": 0."children": [{"name": "Lin"."id": 21."pid": 2."title": The "New generation of migrant workers"
            },
            {
                "name": "Xiao li"."id": 22."pid": 2."title": The "New generation of migrant workers"}]."title": The "New generation of migrant workers"}]Copy the code

Tree node deletes attributes

The sample

Here we directly use the run result of the above — tree structure node to add attributes

methods

const removeAttrFromNode = (tree) = > {
    tree.forEach((item) = > {
        delete item.title
        if (item.children && item.children.length > 0) {
            removeAttrFromNode(item.children)
        }
    })
    return tree
}
Copy the code

The results

const result = removeAttrFromNode(tree);
console.log(result);

// Run the result[{"name": "Xiao Ming"."id": 1."pid": 0."children": [{"name": "Flower"."id": 11."pid": 1."children": [{"name": "Wah"."id": 111."pid": 11
                    },
                    {
                        "name": "Xiao li"."id": 112."pid": 11}]}, {"name": "Little red"."id": 12."pid": 1}]}, {"name": "Wang"."id": 2."pid": 0."children": [{"name": "Lin"."id": 21."pid": 2
            },
            {
                "name": "Xiao li"."id": 22."pid": 2}}]]Copy the code

Delete empty children from the tree

The sample

const tree = [
    {
        name: 'Ming'.id: 1.pid: 0.children: [{name: 'flower'.id: 11.pid: 1.children: [{name: 'xiaohua'.id: 111.pid: 11}, {name: 'xiao li'.id: 112.pid: 11.children: []}]}, {name: 'little red'.id: 12.pid: 1.children: []}]}, {name: 'wang'.id: 2.pid: 0.children: [{name: 'xiao Lin'.id: 21.pid: 2}, {name: 'xiao li'.id: 22.pid: 2.children: []}]}]Copy the code

methods

const removeEmptyChildren = (tree) = > {
    tree.forEach((item) = > {
        if (item.children && item.children.length ===0) {
            delete item.children
        } else if (item.children && item.children.length > 0) {
            removeEmptyChildren(item.children)
        }
    })
    return tree
}
Copy the code

The results

const result = removeEmptyChildren(tree);
console.log(result);

// Run the result[{"name": "Xiao Ming"."id": 1."pid": 0."children": [{"name": "Flower"."id": 11."pid": 1."children": [{"name": "Wah"."id": 111."pid": 11
                    },
                    {
                        "name": "Xiao li"."id": 112."pid": 11}]}, {"name": "Little red"."id": 12."pid": 1}]}, {"name": "Wang"."id": 2."pid": 0."children": [{"name": "Lin"."id": 21."pid": 2
            },
            {
                "name": "Xiao li"."id": 22."pid": 2}}]]Copy the code

Gets all the leaf nodes in the tree

The sample

const tree = [
    {
        name: 'Ming'.id: 1.pid: 0.children: [{name: 'flower'.id: 11.pid: 1.children: [{name: 'xiaohua'.id: 111.pid: 11}, {name: 'xiao li'.id: 112.pid: 11,}]}, {name: 'little red'.id: 12.pid: 1,}]}, {name: 'wang'.id: 2.pid: 0.children: [{name: 'xiao Lin'.id: 21.pid: 2}, {name: 'xiao li'.id: 22.pid: 2,}]}]Copy the code

methods

const getAllLeaf = (tree) = > {
    const result = []
    const getLeaf = (tree) = > {
        tree.forEach((item) = > {
            if(! item.children) { result.push(item) }else {
                getLeaf(item.children)
            }
        })
    }
    getLeaf(tree)
    return result
}
Copy the code

The results

const result = getAllLeaf(tree);
console.log(result);

// Run the result[{"name": "Wah"."id": 111."pid": 11
    },
    {
        "name": "Xiao li"."id": 112."pid": 11
    },
    {
        "name": "Little red"."id": 12."pid": 1
    },
    {
        "name": "Lin"."id": 21."pid": 2
    },
    {
        "name": "Xiao li"."id": 22."pid": 2}]Copy the code

reference

wintc.top/article/20

www.cnblogs.com/mengff/p/13…

Blog.csdn.net/susuzhe123/…

Blog.csdn.net/web_yueqian…

The last

This article has put together a series of JavaScript tree manipulation methods, as a summary of the usual. You can use it, or according to the actual business reference modification.

If you have a better way to implement, or their own encountered in the development, but the above is not involved, welcome to put forward, we discuss together progress ~