简体   繁体   中英

Filter JSON data with recursive parent-child relationship

I have a JSON parent-child recursive structure made like in the example below.

How can I filter this JSON list to exclude just the object corresponding to a selected index?

 familyTree =[
  {
    name: "parent",
    index:"0",
    age:"50,
    children: [
         {
            name: "first child",
            index:"0.0",
            age:"30",
            children: [
                {
                    name: "first grandChild",
                    index:"0.0.0",
                    age:"5"
                },
                {
                    name: "second grandChild",
                    index: "0.0.1",
                    age:"2"
                }
            ]
         },
         {
            name: "second child",
            index:"0.1",
            age:"24",
         }
    ]
 }
]

Eg If I want to exclude the element with index "0.0.1" ,my result will be:

 familyTree =[
   {
    name: "parent",
    index:"0",
    children: [
         {
            name: "first child",
            index:"0.0",
            age:"30",
            children: [
                {
                    name: "first grandChild",
                    index:"0.0.0",
                    age:"5"
                }
            ]
         },
         {
            name: "second child",
            index:"0.1",
            age:"24",
         }
    ]
 }
]

I've tried to use ES6 function filter() but it's probably the wrong use since it's not working

     const elemToRemove= familyTree[0].children[0].children[1]; //index: 0.0.1
     familyTree.filter(
        (elem) => JSON.stringify(elem) === JSON.stringify(elemToRemove)
     );

Thank you for your help

Here is a way to solve your problem. The function familyTreeFilterChildrenByIndex checks the index of each element and also runs itself on any children.

 const familyTree =[ { name: "parent", index:"0", age:"50", children: [ { name: "first child", index:"0.0", age:"30", children: [ { name: "first grandChild", index:"0.0.0", age:"5" }, { name: "second grandChild", index: "0.0.1", age:"2" } ] }, { name: "second child", index:"0.1", age:"24", } ] } ] const familyTreeFilterChildrenByIndex = function (familyTree, indexToRemove) { const result = [] for (const parent of familyTree) { if (parent.index === indexToRemove) { continue } else if (parent.children) { result.push({ ...parent, children: familyTreeFilterChildrenByIndex(parent.children, indexToRemove), }) } else { result.push(parent) } } return result } console.log((familyTreeFilterChildrenByIndex(familyTree, '0.0.1')))

Here's one possibe implementation of filterRec -

function filterRec (t, f)
{ const many = (t = []) =>
    t.flatMap(one)

  const one = (t = {}) =>
    Boolean(f(t))
      ? [ { ...t, children: many(t.children) } ]
      : []
  
  return many(t)
}

Usage is similar to Array.prototype.filter -

const result =
  filterRec(familyTree, elem => elem.index !== "0.0.1")
  
console.log(JSON.stringify(result, null, 2))
[
  {
    "name": "parent",
    "index": "0",
    "age": "50",
    "children": [
      {
        "name": "first child",
        "index": "0.0",
        "age": "30",
        "children": [
          {
            "name": "first grandChild",
            "index": "0.0.0",
            "age": "5",
            "children": []
          }
        ]
      },
      {
        "name": "second child",
        "index": "0.1",
        "age": "24",
        "children": []
      }
    ]
  }
]

Expand the snippet below to verify the results in your own browser -

 function filterRec (t, f) { const many = (t = []) => t.flatMap(one) const one = (t = {}) => Boolean(f(t)) ? [ { ...t, children: many(t.children) } ] : [] return many(t) } const familyTree = [{name:"parent",index:"0",age:"50",children:[{name:"first child",index:"0.0",age:"30",children:[{name:"first grandChild",index:"0.0.0",age:"5"},{name:"second grandChild",index:"0.0.1",age:"2"}]},{name:"second child",index:"0.1",age:"24"}]}] const result = filterRec(familyTree, elem => elem.index !== "0.0.1") console.log(JSON.stringify(result, null, 2))

If you will always be accessing/removing elements by their index you can use it as an address to access the item and return it at the same time as removing it. This solution edits the original array in place.

const indexToRemove = '0.0.1';
const keys = indexToRemove.split('.').map((e, i, a) => a.slice(0, i+1).join('.'));
// ['0', '0.0', '0.0.1']

const removedItem = keys.reduce((a, k, i) => {
  if (i !== keys.length-1) {
    a = a.find(e => e.index === k).children;
  } else {
    const ri = a.map(e => e.index).indexOf(k);
    a = a.splice(ri, 1);
  }
  return a;
}, familyTree);

 const familyTree =[ { name: "parent", index:"0", age:"50", children: [ { name: "first child", index:"0.0", age:"30", children: [ { name: "first grandChild", index:"0.0.0", age:"5" }, { name: "second grandChild", index: "0.0.1", age:"2" } ] }, { name: "second child", index:"0.1", age:"24", } ] } ] const indexToRemove = '0.0.1'; const keys = indexToRemove.split('.').map((e, i, a) => a.slice(0, i+1).join('.')); const removedItem = keys.reduce((a, k, i) => { if (i !== keys.length-1) { a = a.find(e => e.index === k).children; } else { const ri = a.map(e => e.index).indexOf(k); a = a.splice(ri, 1); } return a; }, familyTree); console.log(removedItem); console.log(familyTree);

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