Andrei Shevelev
Andrei Shevelev

Reputation: 3

Filter deeply nested array

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.

Upvotes: 0

Views: 80

Answers (4)

Dmytro Demianenko
Dmytro Demianenko

Reputation: 387

I would use nested forEach

It's not that smart as recursive method, but more readable

function filter(array) {
  const filteredArray = [];

  array.forEach(page => {
    page.elements.forEach(el => {
      el.buttons.forEach(btn => {
        if (btn?.type === "DropDown") {
          btn.options.forEach(opt => {
            if (opt.navigation === true) {
              filteredArray.push(opt);
            }
          });
        } else if (btn.navigation === true) {
          filteredArray.push(btn);
        }
      })
    })
  });

  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));

Upvotes: 0

Nusrat Jahan
Nusrat Jahan

Reputation: 76

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);

Upvotes: 0

symlink
symlink

Reputation: 12209

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)

Upvotes: 0

trincot
trincot

Reputation: 349946

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);

Upvotes: 3

Related Questions