65

So, I'm using Jquery and have two arrays both with multiple values and I want to check whether all the values in the first array exist in the second.

For instance, example 1...

Array A contains the following values

34, 78, 89

Array B contains the following values

78, 67, 34, 99, 56, 89

This would return true

...example 2:

Array A contains the following values

34, 78, 89

Array B contains the following values

78, 67, 99, 56, 89

This would return false

...example 3:

Array A contains the following values

34, 78, 89

Array B contains the following values

78, 89

This would return false

So far I have tried to solve this by:

  1. Extending Jquery with a custom 'compare' method to compare the two arrays. Problem is this only returns true when the arrays are identical and as you can see from example 1 I want it to return true even if they aren't identical but at least contain the value
  2. using Jquerys .inArray function, but this only checks for one value in an array, not multiple.

Any light that anyone could throw on this would be great.

Community
  • 1
  • 1
Betjamin
  • 785
  • 1
  • 7
  • 6

11 Answers11

113

Native JavaScript solution

var success = array_a.every(function(val) {
    return array_b.indexOf(val) !== -1;
});

You'll need compatibility patches for every and indexOf if you're supporting older browsers, including IE8.


Full jQuery solution

var success = $.grep(array_a, function(v,i) {
    return $.inArray(v, array_b) !== -1;
}).length === array_a.length;

Uses $.grep with $.inArray.


ES2015 Solution

The native solution above can be shortened using ES2015's arrow function syntax and its .includes() method:

let success = array_a.every((val) => array_b.includes(val))
  • The i (index) variable is unused and not needed (at least for the JS solution) – jpoppe Dec 20 '16 at 20:14
  • 1
    @jpoppe: Yep, that param can be elided. My answers are *community wiki*, so feel free to make improvements and additions, just so long as the original intent is respected. –  Dec 20 '16 at 22:07
  • Awesome, +1 for ES6 solution – James Barrett Jul 17 '17 at 09:19
61
function containsAll(needles, haystack){ 
  for(var i = 0; i < needles.length; i++){
     if($.inArray(needles[i], haystack) == -1) return false;
  }
  return true;
}

containsAll([34, 78, 89], [78, 67, 34, 99, 56, 89]); // true
containsAll([34, 78, 89], [78, 67, 99, 56, 89]); // false
containsAll([34, 78, 89], [78, 89]); // false
jpthesolver2
  • 1,107
  • 1
  • 12
  • 22
driangle
  • 11,601
  • 5
  • 47
  • 54
55

A one-liner to test that all of the elements in arr1 exist in arr2...

With es6:

var containsAll = arr1.every(i => arr2.includes(i));

Without es6:

var containsAll = arr1.every(function (i) { return arr2.includes(i); });
pulse0ne
  • 1,032
  • 9
  • 12
17

I noticed that the question is about solving this with jQuery, but if anyone else who is not limited to jQuery comes around then there is a simple solution using underscore js.

Using underscore js you can do:

_.intersection(ArrayA, ArrayB).length === ArrayA.length;

From the docs:

intersection_.intersection(*arrays) Computes the list of values that are the intersection of all the arrays. Each value in the result is present in each of the arrays.

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); => [1, 2]

Ergo, if one of the items in ArrayA was missing in ArrayB, then the intersection would be shorter than ArrayA.

datacarl
  • 2,591
  • 25
  • 21
5

You could take a Set and check all items agains it.

const
    containsAll = (needles, haystack) =>
        needles.every(Set.prototype.has, new Set(haystack));

console.log(containsAll([105, 112, 103], [106, 105, 103, 112]));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

Just for the fun of it, i've implemented something with Array.prototype.reduce() :

let areKeysPresent = function (sourceArray, referenceArray) {
    return sourceArray.reduce((acc, current) => acc & referenceArray.includes(current), true)
}
ludovic D
  • 31
  • 2
2

You could also add a containsAll to Array prototype like this:

Array.prototype.containsAll = function()
{
    return Array.from(arguments).every(i => this.includes(i));
}

Examples:

["apple", "banana", "strawberry"].containsAll("apple", "banana"); // true

["apple", "banana", "strawberry"].containsAll("apple", "kiwi"); // false
Miros
  • 527
  • 1
  • 3
  • 11
  • The opposite thing if someone needs: `return Array.from(arguments).some(i => this.includes(i));`. Now you can change the **containsAll** to **has** :) – Kasir Barati Sep 08 '22 at 07:34
0

If you need a little bit more visibility on which items are in the array you can use this one :

var tools = {
        elem : {},
        arrayContains : function(needles, arrhaystack) {
           if (this.typeOf(needles) === 'array') {
                needle.reduce(function(result,item,$i,array){ // You can use any other way right there.
                    var present = (arrhaystack.indexOf(item) > -1);
                    Object.defineProperty(tools.elem, item, {
                        value : present,
                        writable : true
                    });
                },{})
                return this.elem;
            }
        },        
        typeOf : function(obj) {
            return {}.toString.call(obj).split(' ')[1].slice(0, -1).toLowerCase();
        }
    }

Use it with simply var check = tools.arrayContains([10,'foo'], [1,'foo','bar'])

Then you get the result like

10 : false
foo : true

Then if you need to get only one result if one of them is true you can :

arr = Object.values(check);
(arr.indexOf('true')) ? instru1 : instru2 ;

I don't think that's the better way but it's working & easily adaptable. Considering this example I advise you to make an Object.create(tools) before use it in your way.

0

Using array functions: [].filter and [].includes

Something like this:

[34, 78, 89].filter((v) => {
    return [78, 67, 34, 99, 56, 89].includes(v);
});

This will return an array of the matches items

Then we can compare it with needles array

As a function it will be:

const contains = (haystack, needles) => {
    return haystack.filter((v) => {
        return needles.includes(v);
    }).length === needles.length;
}
0

You can use this simple function (renamed variables as per above answer for easy reading):

function contains(haystack, needles) {

    return needles.map(function (needle) { 
        return haystack.indexOf(needle);
    }).indexOf(-1) == -1;
}
caleb
  • 1,579
  • 12
  • 12
0

Try this.

var arr1 = [34, 78, 89];
var arr2 = [78, 67, 34, 99, 56, 89];

var containsVal = true;
$.each(arr1, function(i, val){
   if(!$.inArray(val, arr2) != -1){
       retVal = false;
       return false;
   }
});

if(containsVal){
    //arr2 contains all the values from arr1 
}
ShankarSangoli
  • 69,612
  • 13
  • 93
  • 124