Home > OS >  Filter deeply nested array
Filter deeply nested array

Time:11-06

Given: an array

    [
        {
          "name": "home page",
          "title": "Find Jobs in Technology",
          "url": "https://www.url1.com/",
          "elements": [
            {
              "category": "navigation",
              "buttons": [
                {
                  "title": "Tech Careers",
                  "type": "DropDown",
                  "options": [
                    {
                      "title": "Job Search",
                      "type": "Button",
                      "navigation": true
                    },
                    {
                      "title": "Career Events",
                      "type": "Button",
                      "navigation": false
                    }
                  ]
                },
                {
                  "title": "Insights",
                  "type": "Link",
                  "navigation": true
                }
              ]
            }
          ]
        },
        {
          "name": "tech careers",
          "title": "careers",
          "url": "https://www.url1.com/careers",
          "elements": [
            {
              "category": "navigation",
              "buttons": [
                {
                  "title": "Login",
                  "type": "Link",
                  "navigation": true
                }
              ]
            }
          ]
        }
    ]

I would like to filter this array using Javascript to get an array of objects with "navigation": true.

Expected filtered array:

[
  {
    "title": "Job Search",
    "type": "Button",
    "navigation": true
  },
  {
    "title": "Insights",
    "type": "Link",
    "navigation": true
  },
  {
    "title": "Login",
    "type": "Link",
    "navigation": true
  }
]

Thanks in advance.

I tried array.filter, but it works for one level of items.

CodePudding user response:

You could make a filterRecursive function that uses recursion to filter in deeper arrays inside the objects in the given input array:

function filterRecursive(hierarchy, predicate) {
    return hierarchy.filter(predicate).concat(
        hierarchy.flatMap(o => 
            Object.values(o).filter(Array.isArray)
                  .flatMap(arr => filterRecursive(arr, predicate))
        )
    );
}

const data = [{"name": "home page","title": "Find Jobs in Technology","url": "https://www.url1.com/","elements": [{"category": "navigation","buttons": [{"title": "Tech Careers","type": "DropDown","options": [{"title": "Job Search","type": "Button","navigation": true},{"title": "Career Events","type": "Button","navigation": false}]},{"title": "Insights","type": "Link","navigation": true}]}]},{"name": "tech careers","title": "careers","url": "https://www.url1.com/careers","elements": [{"category": "navigation","buttons": [{"title": "Login","type": "Link","navigation": true}]}]}];

const result = filterRecursive(data, o => o.navigation === true);
console.log(result);

Here is a small variant, that produces the results in the order that you have in the question:

function filterRecursive(hierarchy, predicate) {
    return hierarchy.flatMap(o => 
        (predicate(o) ? [o] : []).concat(
            Object.values(o).filter(Array.isArray)
                  .flatMap(arr => filterRecursive(arr, predicate))
        )
    );
}

const data = [{"name": "home page","title": "Find Jobs in Technology","url": "https://www.url1.com/","elements": [{"category": "navigation","buttons": [{"title": "Tech Careers","type": "DropDown","options": [{"title": "Job Search","type": "Button","navigation": true},{"title": "Career Events","type": "Button","navigation": false}]},{"title": "Insights","type": "Link","navigation": true}]}]},{"name": "tech careers","title": "careers","url": "https://www.url1.com/careers","elements": [{"category": "navigation","buttons": [{"title": "Login","type": "Link","navigation": true}]}]}];

const result = filterRecursive(data, o => o.navigation === true);
console.log(result);

CodePudding user response:

I wrote it for 5 minutes, I would use nested forEach

It's not that smart, but more readable

function filter(array) {
  const filteredArray = [];
  
  array.forEach(page => {
    page.elements.forEach(el => {
      el.buttons.forEach(btn => {
        // if button contains the navigation prop
        if (btn?.navigation === true) {
          filteredArray.push(btn);
          return;
        }

        // else button contains other options
        btn.options.forEach(opt => {
          if (opt.navigation === true) {
            filteredArray.push(opt);
          }
        });
      })
    })
  });
  
  return filteredArray;
}

const data = [{"name": "home page","title": "Find Jobs in Technology","url": "https://www.url1.com/","elements": [{"category": "navigation","buttons": [{"title": "Tech Careers","type": "DropDown","options": [{"title": "Job Search","type": "Button","navigation": true},{"title": "Career Events","type": "Button","navigation": false}]},{"title": "Insights","type": "Link","navigation": true}]}]},{"name": "tech careers","title": "careers","url": "https://www.url1.com/careers","elements": [{"category": "navigation","buttons": [{"title": "Login","type": "Link","navigation": true}]}]}];
    
console.log(filter(data));

CodePudding user response:

Use a recursive function and add objects to a results array if the key/value pair of the object match the criteria:

const arr=[{name:"home page",title:"Find Jobs in Technology",url:"https://www.url1.com/",elements:[{category:"navigation",buttons:[{title:"Tech Careers",type:"DropDown",options:[{title:"Job Search",type:"Button",navigation:true},{title:"Career Events",type:"Button",navigation:false}]},{title:"Insights",type:"Link",navigation:true}]}]},{name:"tech careers",title:"careers",url:"https://www.url1.com/careers",elements:[{category:"navigation",buttons:[{title:"Login",type:"Link",navigation:true}]}]}]

const res = []

function findNavTrue(arr) {
  arr.forEach(obj => {
    for (let [key, val] of Object.entries(obj)) {
      if (Array.isArray(val)) {
        findNavTrue(val)
      } else if (key === "navigation" && val === true) {
        res.push(obj)
      }
    }
  })
}

findNavTrue(arr)
console.log(res)

CodePudding user response:

Please check it:

let arr = [{name:"home page",title:"Find Jobs in Technology",url:"https://www.url1.com/",elements:[{category:"navigation",buttons:[{title:"Tech Careers",type:"DropDown",options:[{title:"Job Search",type:"Button",navigation:true},{title:"Career Events",type:"Button",navigation:false}]},{title:"Insights",type:"Link",navigation:true}]}]},{name:"tech careers",title:"careers",url:"https://www.url1.com/careers",elements:[{category:"navigation",buttons:[{title:"Login",type:"Link",navigation:true}]}]}]
let nav = [];
arr.map((elem1)=>{
    elem1.elements.map((elem2)=>{
        elem2.buttons.map((elem3)=>{ 
           if(elem3.type == 'DropDown') {
                elem3.options.map((elem4)=>{
                    if(elem4.navigation) nav.push(elem4)
                })
           }
           else if(elem3.navigation) nav.push(elem3)
        })
    })
})
console.log(nav);

  • Related