Home > Mobile >  Filter deeply nested array of objects using map() and filter()
Filter deeply nested array of objects using map() and filter()

Time:11-04

I have the below nested data array. I would like to filter on the second level of children leaving only the children that have a name of either "Assistant" or "Advisor" while keeping the rest of the underlying data structure the same.

data = [{
  "name": "root",
  "median": 60000.0,
  "children": [{
      "name": "Defence",
      "median": 60000.0,
      "children": [{
          "name": "Assistant",
          "median": 30000.0,
        },
        {
          "name": "Advisor",
          "median": 50000.0,
        },
        {
          "name": "Secretary",
          "median": 60000.0,
        },
        {
          "name": "Administrator",
          "median": 60000.0,
        },
        {
          "name": "Assistant",
          "median": 20000.0,
        },
      ]
    },
    {
      "name": "Healthcare",
      "median": 60000,
      "children": [{
          "name": "Manager",
          "median": 80000,
        },
        {
          "name": "Advisor",
          "median": 60000,
        },
        {
          "name": "Legal",
          "median": 20000,
        },
        {
          "name": "Cashier",
          "median": 30000,
        },
      ]
    }
  ]
}]

The desired outcome leaves the upper level children the same while returning the second level children that match "Assistant" and "Advisor".

data = [{
  "name": "root",
  "median": 60000.0,
  "children": [{
      "name": "Defence",
      "median": 60000.0,
      "children": [{
          "name": "Assistant",
          "median": 30000.0,
        },
        {
          "name": "Advisor",
          "median": 50000.0,
        },
        {
          "name": "Assistant",
          "median": 20000.0,
        },
      ]
    },
    {
      "name": "Healthcare",
      "median": 60000,
      "children": [{
          "name": "Advisor",
          "median": 60000,
        },
      ]
    }
  ]
}]

I have tried to use a combination of map() and filter() but it only returns the matching second level children.

var fmatch = ["Assistant", "Advisor"]
console.log(data.map(c=> c.children.map(c => c.children.filter(c => fmatch.includes(c.name)))))

data = data = [{
  "name": "root",
  "median": 60000.0,
  "children": [{
      "name": "Defence",
      "median": 60000.0,
      "children": [{
          "name": "Assistant",
          "median": 30000.0,
        },
        {
          "name": "Advisor",
          "median": 50000.0,
        },
        {
          "name": "Secretary",
          "median": 60000.0,
        },
        {
          "name": "Administrator",
          "median": 60000.0,
        },
        {
          "name": "Assistant",
          "median": 20000.0,
        },
      ]
    },
    {
      "name": "Healthcare",
      "median": 60000,
      "children": [{
          "name": "Manager",
          "median": 80000,
        },
        {
          "name": "Advisor",
          "median": 60000,
        },
        {
          "name": "Legal",
          "median": 20000,
        },
        {
          "name": "Cashier",
          "median": 30000,
        },
      ]
    }
  ]
}]

var fmatch = ["Assistant", "Advisor"]
console.log(data.map(c=> c.children.map(c => c.children.filter(c => fmatch.includes(c.name)))))

CodePudding user response:

You need to use a forEach loop when you're looking to modify the underlying data structure. All Array.prototype.map() does is return a new array based on the criteria provided.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

data = data = [{
  "name": "root",
  "median": 60000.0,
  "children": [{
      "name": "Defence",
      "median": 60000.0,
      "children": [{
          "name": "Assistant",
          "median": 30000.0,
        },
        {
          "name": "Advisor",
          "median": 50000.0,
        },
        {
          "name": "Secretary",
          "median": 60000.0,
        },
        {
          "name": "Administrator",
          "median": 60000.0,
        },
        {
          "name": "Assistant",
          "median": 20000.0,
        },
      ]
    },
    {
      "name": "Healthcare",
      "median": 60000,
      "children": [{
          "name": "Manager",
          "median": 80000,
        },
        {
          "name": "Advisor",
          "median": 60000,
        },
        {
          "name": "Legal",
          "median": 20000,
        },
        {
          "name": "Cashier",
          "median": 30000,
        },
      ]
    }
  ]
}]

var fmatch = ["Assistant", "Advisor"]
data.forEach(c => {
    c.children.forEach(c => {
        c.children = c.children.filter(c => fmatch.includes(c.name))
    })
})
console.log(data)

CodePudding user response:

You can just use a simple loop to iterate each parent and only use filter when needed.

If you still want to use .map() you would need to return the full objects instead of the filtered array only

data = [{
  "name": "root",
  "median": 60000.0,
  "children": [{
      "name": "Defence",
      "median": 60000.0,
      "children": [{
          "name": "Assistant",
          "median": 30000.0,
        },
        {
          "name": "Advisor",
          "median": 50000.0,
        },
        {
          "name": "Secretary",
          "median": 60000.0,
        },
        {
          "name": "Administrator",
          "median": 60000.0,
        },
        {
          "name": "Assistant",
          "median": 20000.0,
        },
      ]
    },
    {
      "name": "Healthcare",
      "median": 60000,
      "children": [{
          "name": "Manager",
          "median": 80000,
        },
        {
          "name": "Advisor",
          "median": 60000,
        },
        {
          "name": "Legal",
          "median": 20000,
        },
        {
          "name": "Cashier",
          "median": 30000,
        },
      ]
    }
  ]
}]

var fmatch = ["Assistant", "Advisor"];

const filteredData = data;
filteredData.forEach(item => {
  item.children.forEach(firstChild => {
    firstChild.children = firstChild.children.filter(c => fmatch.includes(c.name));
  });
});

console.log(filteredData);

  • Related