简体   繁体   中英

Filtering nested array using multiple conditions

I have an array like this

const treeObj = [
    {
      id: 1,
      name: 'Section One',
      items: [
        { id: 1, name: 'Section One Item One' },
        { id: 2, name: 'Section One Item Two' },
        { id: 3, name: 'Section One Item Three' },
      ],
    },
    {
      id: 2,
      name: 'Section Two',
      items: [
        { id: 1, name: 'Section Two Item One' },
        { id: 2, name: 'Section Two Item Two' },
        { id: 3, name: 'Section Two Item Three' },
      ],
    },
    {
      id: 3,
      name: 'Section Three X',
      items: [
        { id: 1, name: 'Section Two Item One' },
        { id: 2, name: 'Section Two Item Two' },
        { id: 3, name: 'Section Two Item Three' },
      ],
    },
    {
      id: 4,
      name: 'Section Four X',
      items: [
        { id: 1, name: 'Section Two Item One' },
        { id: 2, name: 'Section Two Item Two' },
        { id: 3, name: 'Section Two Item Three' },
      ],
    },
    {
      id: 5,
      name: 'Section Three X',
      items: [
        { id: 1, name: 'Section Two Item One' },
        { id: 2, name: 'Section Two Item Two' },
        { id: 3, name: 'Section Two Item Three' },
      ],
    },
    {
      id: 6,
      name: 'Section Four X',
      items: [
        { id: 1, name: 'Section Two Item One' },
        { id: 2, name: 'Section Two Item Two' },
        { id: 3, name: 'Section Two Item Three' },
      ],
    },
  ];

I need to write a search functionality that searches the array with an input. I need to check whether string typed is matching each the outer name or any of the name inside items in each section.

Like: str === treeObj[0].name or str in any one of treeObj.items[].name

I need the output in same structure. I'm familiar with filter. But i cant find the right way to do this, checking both section name and item names.

Search the array with a string whether it matches eahc section naem or any one of names in items inside

Can someone point me in the right direction?

UPDATE

I tried this

 const searchStr = searchText.toLowerCase();
    filteredData = data.filter(obj => {
      if (obj.name.toLowerCase().includes(searchStr)) {
        return true;
      }
      if (obj.items.find(item => item.name.toLowerCase().includes(searchStr))) {
        return true;
      }
      return false;
    });

But it returns all items in a section. doesn't filter each section. I need to search to work for both section and items (Try searching an item like: Section One Item One)

You can use a combination of find and filter :

const str = "Section One Item One"

const filter = treeObj.filter(obj => {
  if(obj.name == str) {
    return true
  } else if(obj.items.find(item => item.name == str)) {
    return true
  } else {
    return false;
  }
})

console.log(filter)

Here is a codepen with the code.

EDIT I updated my original algorithm to better fit your needs:

const str = "Section One Item One"
let res = null

const filter = treeObj.some(obj => {
  if(obj.name == str) {
    res = obj;
    return true
  } 

  const item = obj.items.find(item => item.name == str);
  if(item) {
    res = {...obj, items: [item] }
    return true
  }
    return false;
});

console.log(res);

As suggested in the comments by guyjob , I now use some to improve speed. When it finds a match, the search will be aborted. As some only returns true or false , I created a new res variable, which will contain the result of the search. In case of a match it will set res to the whole item if the name was found or filter all but the found element, when it was one of the subitems. I also updated the codepen.

You can filter it out by matching name:

 var treeObj = [ { id: 1, name: 'Section One', items: [ { id: 1, name: 'Section One Item One' }, { id: 2, name: 'Section One Item Two' }, { id: 3, name: 'Section One Item Three' }, { id: 3, name: 'Section One Item Four' } ], }, { id: 2, name: 'Section Two', items: [ { id: 1, name: 'Section Two Item One' }, { id: 2, name: 'Section Two Item Two' }, { id: 3, name: 'Section Two Item Three' }, ], }, { id: 3, name: 'Section Three X', items: [ { id: 1, name: 'Section Two Item One' }, { id: 2, name: 'Section Two Item Two' }, { id: 3, name: 'Section Two Item Three' }, ], }, { id: 4, name: 'Section Four X', items: [ { id: 1, name: 'Section Two Item One' }, { id: 2, name: 'Section Two Item Two' }, { id: 3, name: 'Section Two Item Three' }, ], }, { id: 5, name: 'Section Three X', items: [ { id: 1, name: 'Section Two Item One' }, { id: 2, name: 'Section Two Item Two' }, { id: 3, name: 'Section Two Item Three' }, ], }, { id: 6, name: 'Section Four X', items: [ { id: 1, name: 'Section Two Item One' }, { id: 2, name: 'Section Two Item Two' }, { id: 3, name: 'Section Two Item Three' }, ], }, ]; var strToSearch = 'Four'; var result = treeObj.filter(k=>k.name.includes(strToSearch) || k.items.some(s=>s.name.includes(strToSearch))); console.log(result);

 filteredData = data
      .filter((element, index) => {
        const target = isSectionMatching.findIndex(item => item.id === element.id);
        isSectionMatching[target].match = element.name.toLowerCase().includes(searchStr);
        return (
          element.items.some(subElement => subElement.name.toLowerCase().includes(searchStr)) ||
          isSectionMatching[index].match
        );
      })
      .map((element, index) => {
        const target = isSectionMatching.findIndex(item => item.id === element.id);
        if (isSectionMatching[target].match) {
          return element;
        }
        return {
          ...element,
          items: element.items.filter(subElement => subElement.name.toLowerCase().includes(searchStr)),
        };
      });
  } else {
    filteredData = [...data];
  }

I had a custom requirement, so i was able to find a solution by combining all the answers i got to this question

Thanks to All contributors

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