44

I'm using JavaScript, and would like to check whether an array exists in an array of arrays.

Here is my code, along with the return values:

var myArr = [1,3];
var prizes = [[1,3],[1,4]];
prizes.indexOf(myArr);
-1

Why?

It's the same in jQuery:

$.inArray(myArr, prizes);
-1

Why is this returning -1 when the element is present in the array?

2
  • See this example: jsfiddle.net/DUTTw Commented Oct 23, 2013 at 13:50
  • You can not compare two unique objects with the equality operator, you need to perform a deep equality check. Some libraries offer such a function, or here is one that I put together that you may find useful. Commented Oct 23, 2013 at 14:00

11 Answers 11

51

You can use this

 var a = [ [1,2] , [3,4] ];
 var b = [1,2];
 a = JSON.stringify(a);
 b = JSON.stringify(b);

then you can do just an indexOf() to check if it is present

var c = a.indexOf(b);
if(c != -1){
    console.log('element present');
}
Sign up to request clarification or add additional context in comments.

4 Comments

@Pirijan this would be really elegant if it worked, but it doesn't, JSON.stringify(a) returns [null] then the check fails.
@crclayton there was supposed to be a comma separating the 2 arrays ,i guess i made a mistake while posting the answer, it should work now
A bit late to the party here, but this is beautiful and absolutely should be the accepted answer for it's simplicity.
I'm a bit late, but this would still work if a was something like, [[[1,2]],[3,4]], which is not the intended result.
22

Because [1,3] !== [1,3], since objects will only equal if they reference the same object. You need to write your own search routine:

function searchForArray(haystack, needle){
  var i, j, current;
  for(i = 0; i < haystack.length; ++i){
    if(needle.length === haystack[i].length){
      current = haystack[i];
      for(j = 0; j < needle.length && needle[j] === current[j]; ++j);
      if(j === needle.length)
        return i;
    }
  }
  return -1;
}

var arr = [[1,3],[1,2]];
var n   = [1,3];

console.log(searchForArray(arr,n)); // 0

References

  • Using the Equality Operators:

    If both operands are objects, they're compared as objects, and the equality test is true only if both refer the same object.

4 Comments

for(var i in haystack ){ instead of for(i = 0; i < haystack.length; ++i){ will not throw exception if haystack[1] is missing and haystack[0] and haystack[2] are defined - still returns i=2 if the needle matches haystack[2]
@BharathParlapalli: If haystack[1] is missing, then haystack is not a valid array, and therefor not a suitable candidate for searchForArray.
Tests "[1,3] == [1,3]" in the console... Wat.
This shortcut of the for loop will fail in most ESLint configurations.
14

You could iterate the array of arrays with Array#some and then check every item of the inner array with the single array with Array#every.

var array = [1, 3],
    prizes = [[1, 3], [1, 4]],
    includes = prizes.some(a => array.every((v, i) => v === a[i]));

console.log(includes);

1 Comment

This is a neat one! But be aware that if array has a length of 0, it always will return true, and I don't think you want that. So, you should really add the array.length && before array.every(...
5

Because both these methods use reference equality when operating on objects. The array that exists and the one you are searching for might be structurally identical, but they are unique objects so they won't compare as equal.

This would give the expected result, even if it's not useful in practice:

var myArr = [1,3];
var prizes = [myArr,[1,4]];
prizes.indexOf(myArr);

To do what you wanted you will need to write code that explicitly compares the contents of arrays recursively.

Comments

2
function checkArrayInArray(arr, farr){
    if(JSON.stringify(arr).includes(JSON.stringify(farr))) return true;
    return false;
}

Comments

1

Because javascript objects are compared by identity, not value. So if they don't reference the same object they will return false.

You need to compare recursively for this to work properly.

Comments

1

first define a compare function for arrays

// attach the .compare method to Array's prototype to call it on any array
Array.prototype.compare = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time
    if (this.length != array.length)
        return false;

    for (var i = 0; i < this.length; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].compare(array[i]))
                return false;
        }
        else if (this[i] != array[i]) {
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;
        }
    }
    return true;
}

second just find the array with

prizes.filter(function(a){ return a.compare(myArr)})

NOTE: check the browser compatibility for array.filter

Comments

1

Not a js expert, but just figured out how to do this with Array.every and Array.some

To find the indices of matches:

let anarr = ['a',1, 2]
let arrofarrs = [['a',1, 2], [2,3,4]]

arrofarrs.map(
  subarr => subarr.every(
    (arr_elem, ind) => arr_elem == anarr[ind]
  )
)

// output
// Array [ true, false ]

And to check true/false if the array contains a subarray just change map to some

arrofarrs.some(
  subarr => subarr.every(
    (arr_elem, ind) => arr_elem == anarr[ind]
  )
)
// output
// true

ofc that only works for a single layer of nesting, but could be made recursive ;)

Comments

0

Assuming you are only dealing with a two-dimensional array (you mention an "array of arrays" but nothing deeper than that), this non-recursive code should do what you need.

var compare_arrays = function (array_a, array_b) {
    var rtn = true,
        i, l;
    if (array_a.length === array_b.length) {
        for (i = 0, l = array_a.length; (i < l) && rtn; i += 1) {
            rtn = array_a[i] === array_b[i];
        }
    } else {
        rtn = false;
    }
    return rtn;
},
indexOfSimilarArray = function (arrayToFind, arrayToSearch) {
    var i = arrayToSearch.length,
        chk = false;
    while (i && !chk) {
        i -= 1;
        chk = compare_arrays(arrayToFind, arrayToSearch[i]);
    }
    return i;
};

// Test
var myArr = [1,3];
var prizes = [[1,3],[1,4]];
indexOfSimilarArray(myArr, prizes);

JSFiddle: http://jsfiddle.net/guypursey/V7XpE/. (View the console to see the result.)

Comments

0
function doesArrayOfArraysContainArray (arrayOfArrays, array){
  var aOA = arrayOfArrays.map(function(arr) {
      return arr.slice();
  });
  var a = array.slice(0);
  for(let i=0; i<aOA.length; i++){
    if(aOA[i].sort().join(',') === a.sort().join(',')){
      return true;
    }
  }
  return false;
}

Worth noting:

  • aOA[i].sort().join(',') === a.sort().join(',') is a useful way to check for arrays that contain the same values in the same order, but are references to different objects.

  • array.slice(0) creates a non-referential copy of the original 2D array.

  • However, to create a copy of a 3D array arrayOfArrays.slice(0) does not work; the reference chain will still be present. In order to create a non-referential copy the .map function is necessary.

If you don't create these non-referential array copies you can really run into some tough to track down issues. This function should operate as a conditional and not effect the initial objects passed in.

Javascript is one fickle mistress.

Comments

-1

Use js Maps, have a hash of the array as keys and actual arrays as values, if you need to iterate through all the arrays you can do map.values(). if u need to see if an array exists just calculate the hash o(n) and lookup o(1).

hash function can be as simple as concatinating all the elements with '-' , if your array size is huge, make a number from that array ([1,2] => 12) , and use mod of a big prime number, for collision chain them.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.