0

I have an array of items items[]. Each one has a boolean property filtered and a property that is an array called tags[].

I also have another array: selected_tags.

With this loop, I can filter all items based on the selected tags:

items.forEach(function (item) {

    if (selected_tags.length > 0)
        tag_filter = !selected_tags.some(tag => item.tags.includes(tag));

    // ... other_filter = something else...

    item.filtered = !(!tag_filter && !other_filter);

});

This works with a ANY logic (if any tag is in the selected ones, show the item). I'd like to do this with an ALL logic (if all the selected tags are in the item tags, then show it).

So, naturally, I was wondering if includes can do something like this:

[1,2,3].includes([1,2,3])

[1,2,3].includes(1,2,3)

tag_filter = item.tags.includes(selected_tags);

But it gives false.

Can I do this while keeping it as a simple one liner that returns tag_filter = true if filtered and false if not?

Saturnix
  • 10,130
  • 17
  • 64
  • 120
  • 2
    `!(!tag_filter && !other_filter)` using DeMorgan's law, this can be transformed to the a lot more readable `tag_filter || other_filter` – VLAZ Sep 10 '19 at 15:48

4 Answers4

1

You can use .every() instead of .some()

Eg:

[1,2,3].every(x => [1,2,3].includes(x))

Also, you can change

item.filtered = !(!tag_filter && !other_filter)

to

item.filtered = tag_filter || other_filter
Vandesh
  • 6,368
  • 1
  • 26
  • 38
1

Array::every()

[1, 2, 3].every(function(item) { return [1, 2, 3].includes(item)) }

Or the same for ES6:

[1, 2, 3].every(item => [1, 2, 3].includes(item))
1

Actually you are checking if one array is subset of other. For this you need to use every() and includes(). The time complexity will be O(m * n)

function isSubsetOf(a, b){
  return b.every(x => a.includes(x));
}
console.log(isSubsetOf([1,2,3], [1,2,3]))
console.log(isSubsetOf([1,2,3], [1,2,3, 4]))

For linear O(N) time-complexity first convert the main array to Set and then use Set.prototype.has

function isSubsetOf(a, b){
  a = new Set(a)
  return b.every(x => a.has(x));
}
console.log(isSubsetOf([1,2,3], [1,2,3]))
console.log(isSubsetOf([1,2,3], [1,2,3, 4]))
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
1

So basically, you're looking for something more strict than some(), that is I'd say every(). So simply change this:

tag_filter = !selected_tags.some(tag => item.tags.includes(tag));

To this:

tag_filter = !selected_tags.every(tag => item.tags.indexOf(tag) !== -1);

This piece item.tags.indexOf(tag) !== -1 can be read as "tag exists in item.tags so it's index is not -1".

Hope this helps!

  • `item.tags.indexOf(tag) !== -1` why do that when the code already uses `.includes`? – VLAZ Sep 10 '19 at 15:57
  • @VLAZ good point, it's just that I'm used to `.indexOf()` more often though they don't differ much according to [this](https://stackoverflow.com/questions/35370222/array-prototype-includes-vs-array-prototype-indexof). – Mohammed Mortaga Sep 10 '19 at 16:02