Dileet
Dileet

Reputation: 2064

ES6 .filter() that will return an array of objects WITHOUT certain strings

I'm able to successfully return an array based on if it contains a tag that equals === 'Featured'. Here is the code:

  getFeatured() {
    return blogPosts.filter((item) => (
      item.tags.some((value) => value === 'Featured')
    ))

  }

This filters each blog post, then I use .some() on the array of tags within the post.

I need to now create a function that returns an array of posts that don't contain the word "Featured".

Here is the function so far:

  renderRegular() {
    const regularPost = blogPosts.filter((item) => (
      item.tags.find((value) => value !== 'Featured' )
    ))

    console.log(regularPost)

  }

Upvotes: 4

Views: 2152

Answers (4)

Danziger
Danziger

Reputation: 21161

You need to use Array.prototype.every() instead of Array.prototype.find(), which will return true if all the elements satisfy the predicate. In this case, if all the tags (every tag) are not equal to 'Featured' or, put in a different way, if none of the tags is equal to 'Featured' (see also @Barmar's answer):

const posts = [{
  title: 'Post 1',
  tags: ['Featured'],
}, {
  title: 'Post 2',
  tags: ['Foo', 'Featured'],
}, {
  title: 'Post 3',
  tags: ['Bar'],
}];

const regularPost = posts.filter(item =>
  item.tags.every(value => value !== 'Featured'));

console.log(regularPost);

The advantage of this is that you can also check conditions other than equal or not equal easily:

const posts = [{
  title: 'Post 1',
  tags: ['Featured'],
}, {
  title: 'Post 2',
  tags: ['Foo', 'FEATURED POSTS'],
}, {
  title: 'Post 3',
  tags: ['Bar'],
}];

const regularPost = posts.filter(item =>
  item.tags.every(value => !value.match(/featured/gi)));

console.log(regularPost);

But if you are only doing an equality comparison, Array.prototype.indexOf() or Array.prototype.includes() might be better options:

const posts = [{
  title: 'Post 1',
  tags: ['Featured'],
}, {
  title: 'Post 2',
  tags: ['Foo', 'Featured'],
}, {
  title: 'Post 3',
  tags: ['Bar'],
}];
  
// const regularPost = posts.filter(item =>
//   item.tags.indexOf('Featured') === -1);

const regularPost = posts.filter(item =>
  !item.tags.includes('Featured'));

console.log(regularPost);

Upvotes: 2

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85545

You may assign the item:

renderRegular() {
    const regularPost = blogPosts.filter((item) => 
      // assign item so the filter will return item matched condition with the find
      item = item.tags.find((value) => value !== 'Featured'
    ))
}

Upvotes: 0

Barmar
Barmar

Reputation: 781068

Simply negating the test is not the way to do this. If the tags are Tag1, Featured, Tag2, your test will succeed because "Tag1" != "Featured".

Instead, you need to negate the result of some() rather than the test inside it.

  renderRegular() {
    return blogPosts.filter((item) => (
      !item.tags.some((value) => value === 'Featured')
    ))
  }

Or you can apply de Morgan's Laws. The opposite of "some X == Y" is "every X != Y":

  renderRegular() {
    return blogPosts.filter((item) => (
      item.tags.every((value) => value !== 'Featured')
    ))
  }

Upvotes: 2

Anurag Awasthi
Anurag Awasthi

Reputation: 6233

find will return first element that matches your condition, as it will return a element i.e. a string which will evaluate to true always. Use indexOf to search for presence of string.

renderRegular() {
    const regularPost = blogPosts.filter((item) => (
      item.tags.indexOf('Featured') === -1
    ))

    console.log(regularPost)
}

Upvotes: 0

Related Questions