简体   繁体   中英

Compare tree data in javascript

I have two tree structures one is source tree that contains all leafs, other one CALLED selected , this is just a copy of source tree and missing some leafs, I need to compare source tree and selected and get output same as source but just update the leafs with comparing it with selected . Like any source leaf contains same children then I the want to update source leaf with state: full . If no children is selected state is state: no , if some children is selected state: partial .

I have try to flat the selected tree into array of ids, so i can match the selected ones with source , but I'm stuck in the logic of updating the output tree. please check my expected output.

 const recursCollectIds = ({tree}) => { return (tree || []) .map(leaf => { return (leaf.children && leaf.children.length) ? [leaf.id].concat(recursCollectIds({tree: leaf.children})) : [leaf.id] } ) .flatMap(x => x) } const selected = [{ id: 4, name: 'F', children: [{ id: 8, name: 'V', children: [] }, { id: 9, name: 'T', children: [] }] }, { id: 5, name: 'B', children: [{ id: 17, name: 'R', children: [] }] }, { id: 7, name: 'O', children: [{ id: 90, name: 'Y', children: [{ id: 37, name: 'FU', children: [] }] }] } ] const source = [{ id: 4, name: 'F', children: [{ id: 8, name: 'V', children: [{ id: 3, name: 'F', children: [] }] }, { id: 9, name: 'T', children: [] }] }, { id: 5, name: 'B', children: [{ id: 17, name: 'R', children: [] }] }, { id: 7, name: 'O', children: [{ id: 90, name: 'Y', children: [{ id: 37, name: 'FU', children: [] }] }] } ] const updateTree = ({source, selected}) => { const selectedIds = recursCollectIds({tree: selected}) // need to check with ids of selected and source tree } updateTree({source, selected}) 

Expected output

    const out = [{
        state: 'partial', // due to its children or grand children is selected partially
        id: 4,
        name: 'F',
        children: [{
            state: 'partial', // due to its children or grand children is selected partially
            id: 8,
            name: 'V',
            children: [{
                state: 'no', // due to non of its children selected
                id: 3,
                name: 'F',
                children: []
            }]
        }, {
            state: 'full', // no children so no need to match. 
            id: 9,
            name: 'T',
            children: []
        }]
    },
    {
        state: 'full',
        id: 5,
        name: 'B',
        children: [{
            state: 'full',
            id: 17,
            name: 'R',
            children: []
        }]
    },
    {
        state: 'full',
        id: 7,
        name: 'O',
        children: [{
            state: 'full',
            id: 90,
            name: 'Y',
            children: [{
                state: 'full',
                id: 37,
                name: 'FU',
                children: []
            }]
        }]
    }
]

 const isUndefined = val => ((typeof val == "undefined") && (val == null)); const isArray = val => ((!isUndefined(val)) && (Array.isArray(val))); const modifyObject = tree => { let respObject = {}; (isArray(tree) ? tree : []).forEach(leaf => { respObject[leaf.id] = leaf; if(!isUndefined(leaf.children) && (leaf.children.length > 0)) { respObject[leaf.id]["children"] = modifyObject(leaf.children) } }); return respObject; } const constructResp = (source,selected) => { return (isArray(source) ? source : []).map(currentElem=>{ let currSourceChild = currentElem.children; currSourceChild = isUndefined(currSourceChild) ? [] : currSourceChild; let currElemSelectedChild = selected[currentElem.id]; if(isUndefined(currElemSelectedChild)){ currentElem['state'] = 'no'; return currentElem; } else if(currSourceChild.length == 0){ currentElem['state'] = 'full'; return currentElem; } else{ let currSourceUpdatedChild = constructResp(currSourceChild,currElemSelectedChild.children); let currIndex = 0; let childLen = currSourceUpdatedChild.length; for(;currIndex<childLen;currIndex++){ if(currSourceUpdatedChild[currIndex].state != 'full'){ break; } } if(currIndex == childLen){ currentElem['state'] = 'full'; } else { currentElem['state'] = 'partial'; } return currentElem; } }) } const selected = [{ id: 4, name: 'F', children: [{ id: 8, name: 'V', children: [] }, { id: 9, name: 'T', children: [] }] }, { id: 5, name: 'B', children: [{ id: 17, name: 'R', children: [] }] }, { id: 7, name: 'O', children: [{ id: 90, name: 'Y', children: [{ id: 37, name: 'FU', children: [] }] }] } ] const source = [{ id: 4, name: 'F', children: [{ id: 8, name: 'V', children: [{ id: 3, name: 'F', children: [] }] }, { id: 9, name: 'T', children: [] }] }, { id: 5, name: 'B', children: [{ id: 17, name: 'R', children: [] }] }, { id: 7, name: 'O', children: [{ id: 90, name: 'Y', children: [{ id: 37, name: 'FU', children: [] }] }] } ] const updateTree = ({source, selected}) => { let modifiedSelected = modifyObject(selected) let finalResp = constructResp(source,modifiedSelected); console.log(JSON.stringify(finalResp,null,4)); } updateTree({source, selected}) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM