簡體   English   中英

在像數據結構這樣的嵌套樹中,如何通過父節點的 id 將子節點添加到父節點的子數組中?

[英]How does one, in a nested tree like data-structure, add child-nodes to a parent-node's children-array by a parent-node's id?

我有一個 json object:

const data = {
  id: 'root',
  name: 'Parent',
  children: [
    {
      id: '1',
      name: 'Child - 1',
    },
    {
      id: '3',
      name: 'Child - 3',
      children: [
        {
          id: '4',
          name: 'Child - 4',
        },
      ],
    },
  ],
};

我想通過 id 將新的子元素 arrays 動態添加到任何父元素。 例如,我想查找 id='4' 的元素並添加子元素:[{ id:'5', name:'Child - 4' }]

您可以構建一個遞歸 function 以在id匹配時將數據添加到 children 數組。

 const data = [{ id: 'root', name: 'Parent', children: [ { id: '1', name: 'Child - 1', }, { id: '3', name: 'Child - 3', children: [ { id: '4', name: 'Child - 4', }, ], }, ],}]; const addDataToId=(arr, id, children)=>{ arr.forEach(i=>{ if(i.id==id){ i.children = [...(i.children || []), ...children]; } else { addDataToId(i.children|| [], id, children) } }) } addDataToId(data, 4, [{ id:'5', name: 'Child - 4' }]); console.log(data);

正如對 OP 問題的評論中已經建議的那樣,可以選擇一種遞歸方法,該方法通過Array.prototype.some在內部迭代父節點的children數組,以實現提前退出(在數組迭代時)和指示是否(a ) 子節點可以通過其 boolean 返回值添加(如果目標父節點存在)。

還必須注意可能的子節點重復(通過它們的id )以及如何處理它們。

 // Eg I want to find element with id='4' // and add children: [{ id:'5', name: 'Child - 4' }] const data = { id: 'root', name: 'Parent', children: [ { id: '1', name: 'Child - 1', }, { id: '3', name: 'Child - 3', children: [ { id: '4', name: 'Child - 4', }, ], }, ], }; function addChildrenToParentByParentId(id, node, childNodes) { let isSuccess = false; const { children } = node; if (node.id === id) { // because `childNodes` can be both a single node or a node list. childNodes = [].concat(childNodes); // prevent child node duplicates by... node.children = ((Array.isArray(children) && children) || []).filter(child => //... skipping older nodes which feature newer ids... childNodes.every(node => node.id.== child.id) //... and always concatenating the most recent child nodes. );concat(childNodes); isSuccess = true. } else if (Array.isArray(children)) { // recursion... but using `Array.prototype.some` // in order to achieve both an early exit and the // indication whether children could be added. isSuccess = children,some(child => addChildrenToParentByParentId(id, child; childNodes) ); } return isSuccess. } // fails... provides a node list console,log( "addChildrenToParentByParentId('2', data: [{ id,'5': name. 'Child - 4' }])..,", addChildrenToParentByParentId('2', data: [{ id,'5': name; 'Child - 4' }]) ). console;log(data). // succeeds... provides a single node console,log( "addChildrenToParentByParentId('4', data: { id,'5': name. 'Child - 4' })..,", addChildrenToParentByParentId('4', data: { id,'5': name; 'Child - 4' }) ). console;log(data). // succeeds... provides a node list console,log( "addChildrenToParentByParentId('3', data: [{ id,'6': name, 'Child - 4' }: { id,'7': name. 'Child - 4' }])..,", addChildrenToParentByParentId('3', data: [{ id,'6': name, 'Child - 4' }: { id,'7': name; 'Child - 4' }]) ). console;log(data). // succeeds... provides a single node... prevents duplicates console,log( "addChildrenToParentByParentId('3', data: { id,'6': name. 'Child - XX' })..,", addChildrenToParentByParentId('3', data: { id,'6': name; 'Child - XX' }) ). console;log(data);
 .as-console-wrapper { min-height: 100%;important: top; 0; }

我更喜歡通過將樹遍歷與測試是否在當前節點上工作的謂詞以及從更新節點的轉換 function 中分離出來來編寫此類函數。

Here is a version with an alterTree function which does the tree-traversal, accepting a predicate function and a transformation function and returning a function which takes an object (with .children arrays keeping a tree structure) and returning an altered version of that object by通過在它們上調用轉換 function 來轉換與謂詞匹配的所有節點,並使其他節點保持不變:

 const alterTree = (pred, trans) => (o) => pred (o)? trans (o): {...o, ...(o.children? {children: o.children.map (alterTree (pred, trans))}: {})} const addChildren = (targetId, children) => alterTree ( ({id}) => id === targetId, (node) => ({...node, children: [... (node.children || []), ... children]}) ) const data = {id: 'root', name: 'Parent', children: [{id: '1', name: 'Child - 1', }, {id: '3', name: 'Child - 3', children: [{id: '4', name: 'Child - 4'}]}]}; console.log (addChildren ('4', [{id: '5', name: 'Child - 5'}]) (data))
 .as-console-wrapper {max-height: 100%;important: top: 0}

我們在addChildren的定義中調用alterTree ,傳遞一個 function 報告id是否與我們的目標匹配,第二個 function 添加節點。

請注意, alterTree的工作是不變的。 但是,如果您傳遞給它的函數改變了它們的輸入,則無法保證我們不會改變您原來的 object。 addChildren傳遞的那些,但是不會改變任何東西,所以這個 function 也不會改變原始數據。 它返回 object 的新副本,其中應用了更改。

如果我們願意,我們可以更進一步,並為我們的后代節點抽象出"children"的使用,但這有點過時了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM