最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using array.filter down multiple levels - Stack Overflow

programmeradmin2浏览0评论

I have a filter function, which uses filter to quickly search a text in an array:

filtered = filtered.filter((row) => {
   return Object.keys(row).some((key) => {
        return String(row[key]).toLowerCase().indexOf(this.quickSearch.toLowerCase()) > -1
      })
   })

This works great for single level array, but not sure how to adapt it to work down unknown number of levels of array of objects like this

{
   'name': 'james',
   'post': {
        'name': 'my favorite teams'
    }
}

The code above finds james, no problem, but it will not find teams as its not going deep enough.

Naturally I don't want to hardcode something like if row[key] == 'post', because I'm using this code for multiple data sources and need it to be dynamic.

How do I adapt this to work in multi level arrays like the example above?

I have a filter function, which uses filter to quickly search a text in an array:

filtered = filtered.filter((row) => {
   return Object.keys(row).some((key) => {
        return String(row[key]).toLowerCase().indexOf(this.quickSearch.toLowerCase()) > -1
      })
   })

This works great for single level array, but not sure how to adapt it to work down unknown number of levels of array of objects like this

{
   'name': 'james',
   'post': {
        'name': 'my favorite teams'
    }
}

The code above finds james, no problem, but it will not find teams as its not going deep enough.

Naturally I don't want to hardcode something like if row[key] == 'post', because I'm using this code for multiple data sources and need it to be dynamic.

How do I adapt this to work in multi level arrays like the example above?

Share Improve this question edited Dec 14, 2017 at 23:46 yoyoma asked Dec 14, 2017 at 23:35 yoyomayoyoma 3,5366 gold badges31 silver badges45 bronze badges 4
  • I don't understand how that code would work with the example input you provided. The example you've shown is an object, not an array. The filter method can only be used on arrays. – djfdev Commented Dec 14, 2017 at 23:42
  • sorry the example object above is within the array – yoyoma Commented Dec 14, 2017 at 23:45
  • Is there only one level down (like the example) or there could be more? – ibrahim mahrir Commented Dec 14, 2017 at 23:50
  • one level of array, but multiple objects within objects - sorry I mislabelled the question – yoyoma Commented Dec 14, 2017 at 23:51
Add a ment  | 

2 Answers 2

Reset to default 4

If there are many levels, then recursion is the best solution:

let searchString = this.quickSearch.toLowerCase();                       // do this only once instead of calling toLowerCase over and over again, besides we are using a regular function (not an arrow one) so "this" will be messed up anyways
filtered = filtered.filter(function search(row) {                        // name the function so we can use recursion (thus we can't use an arrow function)
   return Object.keys(row).some((key) => {                               // ...
       if(typeof row[key] === "string") {                                // if the current property is a string
           return row[key].toLowerCase().indexOf(searchString) > -1;     // then check if it contains the search string
       } else if(row[key] && typeof row[key] === "object") {             // oterwise, if it's an object
           return search(row[key]);                                      // do a recursive check
       }
       return false;                                                     // return false for any other type (not really necessary as undefined will be returned implicitly)
   });
});

You could use a recursive function that calls itself on the values of objects and arrays (using Object.values and Array#some):

const containsDeep = (text) => (value) => {
  if(!value) return false;
  const valueType = typeof value;
  
  if(valueType === 'string') {
    return value.toLowerCase().indexOf(text.toLowerCase()) > -1;
  }
  if(Array.isArray(value)) {
    return value.some(containsDeep(text));
  }
  if(valueType === 'object') {
    return Object.values(value).some(containsDeep(text));
  }
  return false;
};

const data = [
  {
   'name': 'bar',
   'post': {
      'name': 'my favorite teams'
    }
  },
  {
    'name': 'fizz',
    'posts': [{'name': 'buzz'}]
  },
  {
    'name': 'bla',
    'post': {
      'name': 'blee',
      'ments': [null, {'name': 'bar'}]
    }
  },
  {
   'name': 'foo',
   'post': {
      'name': 'bar'
    }
  }
];

const result = data.filter(containsDeep('bar'));
console.log(result);

发布评论

评论列表(0)

  1. 暂无评论