Javascript array contains/includes sub array

24,936

Solution 1

With a little help from fromIndex parameter

This solution features a closure over the index for starting the position for searching the element if the array. If the element of the sub array is found, the search for the next element starts with an incremented index.

function hasSubArray(master, sub) {
    return sub.every((i => v => i = master.indexOf(v, i) + 1)(0));
}

var array = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3];

console.log(hasSubArray(array, [777, 22, 22]));
console.log(hasSubArray(array, [777, 22, 3]));
console.log(hasSubArray(array, [777, 777, 777]));
console.log(hasSubArray(array, [42]));

Solution 2

Just came up with quick thought , but efficiency depends on size of the array

var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3];
var sub = [777, 22, 22];

if ((master.toString()).indexOf(sub.toString()) > -1 ){
    //body here
}

Solution 3

var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3]; 

var sub = [777, 22, 22]; 

console.log(master.join(',').includes(sub.join(',')))

//true

You can do this by simple console.log(master.join(',').includes(sub.join(','))) this line of code using include method

Solution 4

EDIT

Misunderstood question initially.

function arrayContainsSub(arr, sub) {
        var first = sub[0],
            i = 0,
            starts = [];

        while (arr.indexOf(first, i) >= 0) {
            starts.push(arr.indexOf(first, i));
            i = arr.indexOf(first, i) + 1;
        }

        return !!starts
                    .map(function(start) {
                        for (var i = start, j = 0; j < sub.length; i++, j++) {
                            if (arr[i] !== sub[j]) {
                                return false;
                            }
                            if (j === sub.length - 1 && arr[i] === sub[j]) {
                                return true;
                            }
                        };

                    }).filter(function(res) {
                        return res;
                    }).length;
    }

This solution will recursively check all available start points, so points where the first index of the sub has a match in the array


Old Answer Kept in case useful for someone searching.

if(master.indexOf(sub) > -1){ //Do awesome stuff }

Important to remember that this will only match of master literally references sub. If it just contains an array with the same contents, but references a different specific object, it will not match.

Solution 5

If the order is important, it has to be an actually sub-array (and not the subset of array) and if the values are strictly integers then try this

console.log ( master.join(",").indexOf( subarray.join( "," ) ) == -1 )

for checking only values check this fiddle (uses no third party libraries)

var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3]; 

var sub = [777, 22, 22]; 

function isSubset( arr1, arr2 )
{
    for (var i=0; i<arr2.length; i++)
    {
        if ( arr1.indexOf( arr2[i] ) == -1 )
        {
          return false;
        }
    }
    return true;
}
console.log( isSubset( master, sub ) );

There are faster options explained here as well.

Share:
24,936
Victor Axelsson
Author by

Victor Axelsson

Studying Software Engineering at Malmö University, Sweeden.

Updated on October 06, 2020

Comments

  • Victor Axelsson
    Victor Axelsson over 3 years

    I need to check if an array contains another array. The order of the subarray is important but the actual offset it not important. It looks something like this:

    var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3]; 
    
    var sub = [777, 22, 22]; 
    

    So I want to know if master contains sub something like:

    if(master.arrayContains(sub) > -1){
        //Do awesome stuff
    }
    

    So how can this be done in an elegant/efficient way?

  • gurvinder372
    gurvinder372 over 8 years
    @zerkms Why you say so? it is working. It outputs 'true'
  • zerkms
    zerkms over 8 years
    Well, for my example it should have returned false
  • gurvinder372
    gurvinder372 over 8 years
    @zerkms got it. take your point. Trying to come up with one now which can handle multiple instances of same value.
  • Victor Axelsson
    Victor Axelsson over 8 years
    This is actually the solution I went with in my implementation and I like it since it simple to understand. But I don't feel like it actually solves the problem because of two reasons: it could use prototype on array and I should get the actual index in the array (and not the string). Thanks!
  • Victor Axelsson
    Victor Axelsson over 8 years
    I like that you used prototype and that it's simple. If you can get it to return the array indexOf I'll be willing to accept as answer.
  • deblocker
    deblocker over 7 years
    What if var master = [12, 44, 22, 66, 222, 777, 22, 224, 22, 6, 77, 3]; var sub = [777, 22, 22];? This would be very dangerous.
  • Alexander Gromnitsky
    Alexander Gromnitsky about 6 years
    doesn't work: it should return false for y==[4,2]
  • mpen
    mpen over 5 years
    sub=[777, 22, 3] returns true. Is that intentional? OP did say "actual offset it not important" but I'm not quite sure what that means.
  • mpen
    mpen over 5 years
    I'm asking you if your code intentionally matches that, because just looking at your example I would have expected [777,22,22] has to be contiguous in the master array, but that's not the case.
  • mpen
    mpen over 5 years
    You've got another issue in there actually. It should index = i + 1 to prevent double-matching on the same character. Otherwise [777, 777, 777] also matches!
  • Nina Scholz
    Nina Scholz over 5 years
    @mpen, ad1 ([777, 22, 3]): yes, it is intentional, because 22 has a greater index than 777 and 3 ahs a greater index of 22. ad2 ([777, 22, 22]): that is true. ad3 ([777, 777, 777]): you are right, the found index has to be incremented.
  • heltonbiker
    heltonbiker about 4 years
    @deblocker it could be something like someArray.map(value => value.toString()).join(";") so that the string would be delimited, avoiding false matches.
  • Tzahi Leh
    Tzahi Leh about 3 years
    _hasSubArray([23,34,45,56], [23,34,23]) // returns true, though should return false
  • Tzahi Leh
    Tzahi Leh about 3 years
    That's a good option if you don't search for the exact order of a subarray. OP mentioned that The order of the subarray is important, but in your case also [1,2,4] returns true