The tree data structure is reversed up and down.

bottom-up multiple pieces of tree structure data are inverted and merged into one or more top-down tree structures

id, with multiple known data gets all the superiors, and then reverses

Raw data rule: the pid of each piece of data is unique

{id:1,pid:0},
{id:2,pid:1},
{id:3,pid:2},
{id:4,pid:3},
{id:5,pid:3},
{id:6,pid:2},
{id:7,pid:1},
< hr >

known id:3,7. The result to be obtained:

    0
    |
    1
   / \
  2   7
 /
3

ideas and principles

get a bottom-up tree structure from id:3,7:

3->2->1->0
7->1->0

and then reverse to the top-down data structure above:

[
    {
        id:1,
        pid:0,
        children:[
            {
                id:2,
                pid:1,
                children:[
                    {
                        {id:3,pid:2}
                    }
                ]
            },
            {
                id:7,
                pid:1
            }
        ]
    }
]
< hr >

so how to implement this process in code programming? Ask all the bosses to take a look at it.

Dec.04,2021

function Node()
{
}
Node.prototype.id   = null;
Node.prototype.prev = null;
Node.prototype.next = null;
Node.prototype.filter = function($mapFilter){

    let i;
    let arr, arrNext = [];
    for(i=0; i<this.next.length; iPP)
    {
        arr = this.next[i].filter($mapFilter);

        if(arr !== null)
            arrNext.push(arr);
    }

    if(arrNext.length <= 0 && (this.id in $mapFilter) === false)
        return null;

    return {
        id : this.id
        ,pid : (this.prev === null)?Tree.ROOT_ID:this.prev.id
        ,children : arrNext
    };
};

function Tree()
{
    this.mapRoot = [];
    this.mapNode = [];
}
Tree.ROOT_ID = 0;
Tree.prototype.mapRoot = null;
Tree.prototype.mapNode = null;
Tree.prototype.add = function($ndi){

    let nodeThis, nodePrev;

    if($ndi.id in this.mapNode === false)
    {
        nodeThis = new Node();
        nodeThis.id = $ndi.id;
        nodeThis.prev = null;
        nodeThis.next = [];

        this.mapNode[$ndi.id] = nodeThis;
    }
    else
        nodeThis = this.mapNode[$ndi.id];

    nodePrev = null;
    if($ndi.pid !== Tree.ROOT_ID)
    {
        if($ndi.pid in this.mapNode === false)
        {
            nodePrev = new Node();
            nodePrev.id = $ndi.pid;
            nodePrev.prev = null;
            nodePrev.next = [];

            this.mapNode[$ndi.pid] = nodePrev;
        }
        else
            nodePrev = this.mapNode[$ndi.pid];

        nodePrev.next.push(nodeThis);
    }

    nodeThis.prev = nodePrev;

    if(nodePrev !== null && nodePrev.id in this.mapRoot === false && nodePrev.prev === null)
        this.mapRoot[nodePrev.id] = nodePrev;

    if(nodeThis.id in this.mapRoot === true && nodeThis.prev !== null)
        delete this.mapRoot[nodeThis.id];
};
Tree.prototype.filter = function($arrFilter){
    let mapFilter = {};
    for(i=0; i<$arrFilter.length; iPP)
        mapFilter[$arrFilter[i]] = $arrFilter[i];

    let data = [];
    let id;
    for(id in this.mapRoot)
    {
        if(this.mapRoot.hasOwnProperty(id) === false)
            continue;

        data.push(this.mapRoot[id].filter(mapFilter));
    }

    return data;
};

let arrNode = [
    { id: 4, pid: 3 },
    { id: 3, pid: 2 },
    { id: 1, pid: 0 },
    { id: 2, pid: 1 },
    { id: 5, pid: 3 },
    { id: 6, pid: 2 },
    { id: 7, pid: 1 },
    { id: 8, pid: 10 },
    { id: 9, pid: 8 },
    { id: 10, pid: 11 },
];

let i;
let tree = new Tree();
//    
for(i=0; i<arrNode.length; iPP)
    tree.add(arrNode[i]);
// 
let data = tree.filter([3,7,9]);

console.log(JSON.stringify(data, null, '  '));

let all = [
    { id: 4, pid: 3 },
    { id: 3, pid: 2 },
    { id: 1, pid: 0 },
    { id: 2, pid: 1 },
    { id: 5, pid: 3 },
    { id: 6, pid: 2 },
    { id: 7, pid: 1 },
    { id: 8, pid: 10 },
    { id: 9, pid: 8 },
    { id: 10, pid: 11 },
]
// id
let getPid = id => {
    let parent = {}
    all.forEach(obj => {
        if (obj.id == id) {
            parent = obj
        }
    })
    return parent
}
// pid
let getParents = (id, parents = []) => {
    if (!id) {
        return parents
    }
    if (parents.indexOf(id) < 0) {
        parents.push(id)
    }
    let pid = getPid(id).pid
    if (parents.indexOf(pid) > -1) {
        return parents
    } else if (pid == 0) {
        // parents.push(id)
        return parents
    } else {
        return getParents(pid, parents)
    }
}

let ids = [3, 7, 9]
// id
let parents = []
ids.forEach(id => {
    parents = getParents(id, parents)
})
console.log(parents)
// [ 3, 2, 1, 7, 9, 8, 10, 11 ]

// hash key
rec = (id, hash) => {
    let obj = hash[id]
    if (obj.pid in hash) {
        if (!('children' in hash[obj.pid])) {
            hash[obj.pid]['children'] = {}
        }
        hash[obj.pid]['children'][obj.id] = JSON.parse(JSON.stringify(obj))
        return rec(obj.pid, hash)
    } else {
        return hash
    }
}
// parents id
let hash = {}
all.forEach(obj => {
    let id = obj.id
    if (parents.indexOf(id) > -1) {
        hash[id] = JSON.parse(JSON.stringify(obj))
    }
})
let keys = Object.keys(hash)
keys.forEach(key => {
    hash = rec(key, hash)
})
let tree = {}
keys.forEach(key => {
    if (!(hash[key].pid in hash)) {
        tree[key] = hash[key]
    }
})
console.log(tree)

results obtained

{
    "1": {
        "id": 1,
        "pid": 0,
        "children": {
            "2": {
                "id": 2,
                "pid": 1,
                "children": {
                    "3": {
                        "id": 3,
                        "pid": 2
                    }
                }
            },
            "7": {
                "id": 7,
                "pid": 1
            }
        }
    },
    "10": {
        "id": 10,
        "pid": 11,
        "children": {
            "8": {
                "id": 8,
                "pid": 10,
                "children": {
                    "9": {
                        "id": 9,
                        "pid": 8
                    }
                }
            }
        }
    }
}

in fact, the given data is very suitable for building a node tree. Each different id is a node. The code is as follows

// 1.
nda = arr.map(v => {
    return { ...v }
})
// 2.
nda.forEach(v => {
    // 
    v.children = nda.filter(child => child.pid == v.id)
    // 
    v.children == 0 && delete v.children
});

find the root node and get the whole tree print

let root = nda.find(item => item.id == 1)
console.log(JSON.stringify(root, null, 2))

effect

{
  "id": 1,
  "pid": 0,
  "children": [
    {
      "id": 2,
      "pid": 1,
      "children": [
        {
          "id": 3,
          "pid": 2,
          "children": [
            {
              "id": 4,
              "pid": 3
            },
            {
              "id": 5,
              "pid": 3
            }
          ]
        },
        {
          "id": 6,
          "pid": 2
        }
      ]
    },
    {
      "id": 7,
      "pid": 1
    }
  ]
}

compared with Filter id, the branch is removed as the leaf node first, and then the sibling node of the non-designated id of the same father, which needs to be recursive, as follows

function filterTree(nd, ids) {
    // 1.id 
    if (ids.includes(nd.id)) {
        nd.children && delete nd.children
    }
    if (nd.children) {
        for (let i = nd.children.length - 1; i >= 0; i--) {
            const element = nd.children[i];
            // 2.
            if (element.children) {
                // 3. 
                filterTree(element, ids)
            } else {
                // 4.
                if (!(ids.includes(element.id))) {
                    nd.children.splice(i, 1)
                }
            }
        }
    }
    return
}

in the end, Filter will be tested as follows, as you want.

filterTree(root, [3, 7])
console.log(JSON.stringify(root, null, 2))

{
  "id": 1,
  "pid": 0,
  "children": [
    {
      "id": 2,
      "pid": 1,
      "children": [
        {
          "id": 3,
          "pid": 2
        }
      ]
    },
    {
      "id": 7,
      "pid": 1
    }
  ]
}
Menu