.every()
will stop processing immediately if the method passed to it returns false
. The above suggestion does the check in the method passed to .map()
, which runs on every element unconditionally. Why not use just .every()
so that negative results are found faster?
Here's some injection that will demonstrate:
let counter;
const includesAllWithMap = (s, ...args) => args.map((v) => {
counter += 1;
return s.includes(v);
}).every(Boolean);
const includesAllWithJustEvery = (s, ...args) => args.every((v) => {
counter += 1;
return s.includes(v);
});
counter = 0;
rc = includesAllWithMap('abcdef', 'ab', 'cd', 'ba', 'ef', 'a', 'c');
console.log('result with map =', rc, 'number of comparisons =', counter);
// result with map = false number of comparisons = 6
counter = 0;
rc = includesAllWithJustEvery('abcdef', 'ab', 'cd', 'ba', 'ef', 'a', 'c');
console.log('result with just every =', rc, 'number of comparisons =', counter);
// result with map = false number of comparisons = 3
To make it succinct:
const includesAll = (s, ...args) => args.every(v => s.includes(v));
> includesAll('abcdef', 'ab', 'cd', 'ba', 'ef', 'a', 'c')
// false
> includesAll('abcd', 'a', 'd')
// true
You can make a slight change if you want to provide the substrings in arrays, as the original poster wanted:
const includesAll = (s, ...args) => args.flat().every(v => s.includes(v));
> includesAll('abcdef', ['ab', 'cd', 'ba'], ['ef', 'a', 'c'])
// false
> includesAll('abcd', ['a', 'd'])
// true
> includesAll('abcdef', ['ab', 'abc'], ['de'], ['bcd'])
// true
And if you want both:
const includesAll = (s, ...args) => args.every(v => s.includes(v));
const includesAllinArrays = (s, ...args) => includeAll(s, args.flat());
And if you want an all-in-one (at the sacrifice of some efficiency):
const includesAll = (s, ...args) => args
.map(a => Array.isArray(a) ? a.flat() : [a])
.flat()
.every(v => s.includes(v));
> includesAll('abcdef', 'ab', 'abc', ['d'], ['d', 'e'], 'cd')
// true