Find a Substring in a JavaScript Array

EDIT (2016/08/10): I’ve received a few comments on twitter and in the lunchroom at work expressing as much interest in the bitwise NOT operator as finding the substring in an array. So I’ve added the !! for type coercion to get actual booleans, and blow your minds even more.


Last week a colleague asked me how to check if a substring exists in a JavaScript array and set that as a boolean flag. Assigning a boolean for the existence of a full string in an array is pretty easy, and I often use something like this in my code:

var arr = [ 'foo', 'bar' ];
var str = 'baz'; 
var isTrue = !!~arr.indexOf( str );
// returns false
str = 'foo';
isTrue = !!~arr.indexOf( str );
// returns true

The bitwise NOT (~) operator inverts the -1 to 0, and the !! operator coerces that value to false when the string is not in the array.

Which is essentially a one-liner for this:

var isTrue = true;
if ( arr.indexOf( str ) === -1 ) {
    isTrue = false;
}

But when you want to check for a partial match of foo.baz for instance, in any part of your array, the above solution won’t work. You’d need to use a regular expression and a loop, or a loop and String.prototype.indexOf(), etc…

Or, you can use ES2015’s Array.protoype.find() (with a Polyfill if required). New array methods have been long overdue in JavaScript and this one has come in handy a few times for me.

Here is how I’d set a similar boolean flag based on a substring existing in an array using Array.prototype.find(), bitwise NOT , !! and String.prototype.indexOf():

var arr = [ 'foo', 'bar' ];
var str = 'food.land';
var isTrue = !!arr.find( function (elem) {
    return !!~str.indexOf( elem );
});
// returns true

If I were to set str = 'bob.builder' then isTrue returns false.

It’s not a perfect solution, as in it’s pretty greedy with the matches, but it’s a pretty good trick in the right situation.

 

Adam Merrifield

 

5 thoughts on “Find a Substring in a JavaScript Array

  1. If you use Array.prototype.find might as well use String.prototype.includes, instead of hacky tildeh indexOf. They are both on ES2015. Besides of more readable, every comp-sci student know what include is.

  2. you could also shorten it with arrow functions

    let result = array.find(e => ~string.indexOf(e));

    or have it return custom true/false values if needed

    let result = (array.find(e => ~string.indexOf(e))) ? 'yep' : 'nope';

    or go too far with it and have it return an object with its custom true/false

    var arr = ['foo', 'bar'];

    function isFound(string, array) {
    let res = array.find(e => ~string.indexOf(e));
    return (res) ? {bool: 'true', value: res} : {bool: false, value: 'not found'};
    }

    let checkFoo = isFound('foo', arr);
    console.log(checkFoo);
    //Object {
    // bool: "true",
    // value: "foo"
    //}

    1. Arrow functions would require transpiling, not just polyfills. But I love the spirit of it.

  3. I think there’s another solution like below:

    var arr = [ 'foo', 'bar' ];
    var str = 'food.land';
    var isTrue = !!arr.some(function (item) {
    return str.indexOf(item) !== -1;
    });

Leave a Reply