How insert item in tree recursively

落爺英雄遲暮 提交于 2020-06-17 15:49:09

问题


I'm trying to create a tree component. But I dont know how insert a item recursively inside a tree.

Each item its created dinamically and I would like instert/create an item/branch of the tree in each level. Problem is that when I cant insert items on level 3.

For example, I have this code generated:

[{
    "id": 0,
    "active": false,
    "favorite": false,
    "level": 0,
    "title": "New Branch 0",
    "editable": false,
    "checkbox": false,
    "checkboxEnabled": false,
    "children": []
}, {
    "id": 1,
    "active": false,
    "favorite": false,
    "level": 0,
    "title": "New Branch 1",
    "editable": false,
    "checkbox": false,
    "checkboxEnabled": false,
    "children": [{
        "id": 3,
        "parentId": 1,
        "active": false,
        "favorite": false,
        "level": 1,
        "title": "New Branch 3",
        "editable": false,
        "checkbox": false,
        "checkboxEnabled": false,
        "children": []
    }, {
        "id": 4,
        "parentId": 1,
        "active": false,
        "favorite": false,
        "level": 1,
        "title": "New Branch 4",
        "editable": false,
        "checkbox": false,
        "checkboxEnabled": false,
        "children": []
    }]
}, {
    "id": 2,
    "active": false,
    "favorite": false,
    "level": 0,
    "title": "New Branch 2",
    "editable": false,
    "checkbox": false,
    "checkboxEnabled": false,
    "children": []
}]

And I'm trying to create a method that insert, for example inside children of New Branch 4 or his children. And that return updated array.

This is my code:

const onCreateChildren = () => {
    let newBranch: IBranch = generateBranch(numBranchs);
    newBranch = Object.assign({}, newBranch, {
        level: level + 1,
        parentId: branch.id,
    });
    let copyChildren: Array<IBranch> = children.slice();
    copyChildren.push(newBranch);
    const updatedBranch: IBranch = Object.assign({}, branch, {
        children: copyChildren,
    });
    if (parentId === undefined) {
        const index: number = branchs.findIndex( (b: IBranch) => b.id === branch.id);
        const updatedBranchs: Array<IBranch> = Object.assign([], branchs, {
            [index]: updatedBranch,
        });
        onUpdateBranchs(updatedBranchs);
    } else {
        const updatedBranchs: any = addBranchInTree(branchs, newBranch);
        onUpdateBranchs(updatedBranchs);
    }

    onUpdateNumBranchs(numBranchs+1);
};

Why doenst work always?? Can someone help me?? Other ideas??

export const addBranchInTree = (branchs: any, branch: IBranch): any => {
    return Array.isArray(branchs)
        ? branchs.map((o: IBranch) => addBranchInTree(o, branch))
        : findNode(branchs, branch);
};

const findNode = (branchs: any, branch: any): any => {
    if (branchs.children.length > 0) {
        branchs.children.forEach((child: any) => {
            return findNode(child, branch);
        });
    }

    if (!Array.isArray(branchs)) {
        if (branchs.parentId === branch.parentId - 1) {
            return branchs.children.push(branch);
        }
    }

    return branchs;
};

回答1:


Similarly to how we did it in an earlier question, we can recursively traverse the object, looking for the item whose id matches our new item's parentId and append the new element to its list of children.

There is a little extra complexity in dealing with an item that has no parentId, which I'm assuming should go on the root. Essentially, if we're in an array and our element has no parentId, we assume we can just append it. This should only happen on the root, if the original data is an array.

const addElement = (obj, el) => 
  Array .isArray (obj) 
    ? 'parentId' in el 
      ? obj .map (o => addElement (o, el))
      : [...obj, el]
  : obj .id === el .parentId 
    ? {...obj, children: [...(obj.children || []), el]}
  : // else
    {...obj, ...('children' in obj ? {children: addElement (obj.children, el)} : {})}

const data = [
  {id: 1, title: 'foo', children: [
    {id: 11, parentId: 1, title: 'bar',},
    {id: 12, parentId: 1, title: 'baz', children: [
      {id: 121, parentId: 12, title: 'qux'},
      {id: 122, parentId: 12, title: 'quz'}
    ]},
    {id: 13, parentId: 1, title: 'corge'}
  ]},
  {id: 2, title: 'grault'}
];

const newItem = {id: 123, parentId: 12, title: 'new element here'}
console .log (addElement (data, newItem))

const motherlessChild = {id: 99, title: 'root element here -- no parentId'}
console .log (addElement (data, motherlessChild))
.as-console-wrapper {min-height: 100% !important; top: 0}

Note (and I didn't point this out on the earlier question) that this does not mutate your data object, returning instead an entirely new one. We also don't deal with the case that the new element has no parentId, or that the tree does not include an element with an id matching the new element's parentId. Those are left as exercises for the reader.

It the matching used above -- checking that the id matches the new element's parentId -- is not correct, could you explain how you do want to find the correct spot to insert it, please?


One other point, and please take this as the constructive criticism that's intended: You've been around StackOverflow for a while. If you haven't read the help center's discussion on creating a minimal, reproducible example, please do so. It seems there is too much code above unrelated to the question you're asking. Especially note your sample data. I was hoping you might get the idea from my earlier answer, but it seems you didn't. You should be able to describe this problem with nodes that have an id, a parentId, children where relevant, and only one more property to demonstrate those parts that aren't specifically noted elsewhere (I used title, but anything would do.) It makes it much easier to answer questions when the extraneous matter has been removed.



来源:https://stackoverflow.com/questions/62177414/how-insert-item-in-tree-recursively

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!