Javascript array contains/includes sub array
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.
Victor Axelsson
Studying Software Engineering at Malmö University, Sweeden.
Updated on October 06, 2020Comments
-
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
containssub
something like:if(master.arrayContains(sub) > -1){ //Do awesome stuff }
So how can this be done in an elegant/efficient way?
-
gurvinder372 over 8 years@zerkms Why you say so? it is working. It outputs 'true'
-
zerkms over 8 yearsWell, for my example it should have returned
false
-
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 over 8 yearsThis 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 over 8 yearsI 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 over 7 yearsWhat 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 about 6 yearsdoesn't work: it should return
false
fory==[4,2]
-
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 over 5 yearsI'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 over 5 yearsYou'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 over 5 years@mpen, ad1 (
[777, 22, 3]
): yes, it is intentional, because22
has a greater index than777
and3
ahs a greater index of22
. ad2 ([777, 22, 22]
): that istrue
. ad3 ([777, 777, 777]
): you are right, the found index has to be incremented. -
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 about 3 years
_hasSubArray([23,34,45,56], [23,34,23]) // returns true, though should return false
-
Tzahi Leh about 3 yearsThat'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