joe_coolish
joe_coolish

Reputation: 7259

Javascript indexOf for an array of arrays not finding array

I have an array with nested arrays that looks like this:

var tw = [[3, 0], [11, 0], [3, 14], [11, 14]];

When I try and find if the array tw contains a passed in array, I always get a result of -1.

For example:

var test = $.inArray([3, 0], tw);
var test2 = tw.indexOf([3, 0]);

both return -1, even though the first object in the array is [3,0] How do I find out if a specific array of arrays is contained in my array?

Oh, and I've only tested it on IE9 so far.

Upvotes: 9

Views: 7976

Answers (6)

dragonfire
dragonfire

Reputation: 702

Why not keep it simple?

function indexOfCustom (parentArray, searchElement) {
    for ( var i = 0; i < parentArray.length; i++ ) {
        if ( parentArray[i][0] == searchElement[0] && parentArray[i][1] == searchElement[1] ) {
            return i;
        }
    }
    return -1;
}

Upvotes: 0

ajax333221
ajax333221

Reputation: 11774

For infinite nested search:

function indexOfArr(arr1, fnd1) {
    var i, len1;

    //compare every element on the array
    for (i = 0, len1 = arr1.length; i < len1; i++) {

        //index missing, leave to prevent false-positives with 'undefined'
        if (!(i in arr1)) {
            continue;
        }

        //if they are exactly equal, return the index
        if (elementComparer(arr1[i], fnd1)) {
            return i;
        }
    }

    //no match found, return false
    return -1;
}

function elementComparer(fnd1, fnd2) {
    var i, len1, len2, type1, type2, iin1, iin2;

    //store the types of fnd1 and fnd2
    type1 = typeof fnd1;
    type2 = typeof fnd2;

    //unwanted results with '(NaN!==NaN)===true' so we exclude them
    if (!((type1 == "number" && type2 == "number") && (fnd1 + "" == "NaN" && fnd2 + "" == "NaN"))) {

        //unwanted results with '(typeof null==="object")===true' so we exclude them
        if (type1 == "object" && fnd1 + "" != "null") {
            len1 = fnd1.length;

            //unwanted results with '(typeof null==="object")===true' so we exclude them
            if (type2 == "object" && fnd2 + "" != "null") {
                len2 = fnd2.length;

                //if they aren't the same length, return false
                if (len1 !== len2) {
                    return false;
                }

                //compare every element on the array
                for (i = 0; i < len1; i++) {

                    iin1 = i in fnd1;
                    iin2 = i in fnd2;

                    //if either index is missing...
                    if (!(iin1 && iin2)) {

                        //they both are missing, leave to prevent false-positives with 'undefined'
                        if (iin1 == iin2) {
                            continue;
                        }

                        //NOT the same, return false
                        return false;
                    }

                    //if they are NOT the same, return false
                    if (!elementComparer(fnd1[i], fnd2[i])) {
                        return false;
                    }
                }
            } else {
                //NOT the same, return false
                return false;
            }
        } else {

            //if they are NOT the same, return false
            if (fnd1 !== fnd2) {
                return false;
            }
        }
    }

    //if it successfully avoided all 'return false', then they are equal
    return true;
}

Notes:

  • supports infinite nested arrays
  • handles sparse arrays correctly
  • uses typeof checks

jsFiddle demo

Upvotes: 2

Tim Down
Tim Down

Reputation: 324707

That's because you're searching for a different object. indexOf() uses strict equality comparisons (like the === operator) and [3, 0] === [3, 0] returns false.

You'll need to search manually. Here's an example using a more generic indexOf() function that uses a custom comparer function (with an improvement suggested by @ajax333221 in the comments):

// Shallow array comparer
function arraysIdentical(arr1, arr2) {
    var i = arr1.length;
    if (i !== arr2.length) {
        return false;
    }
    while (i--) {
        if (arr1[i] !== arr2[i]) {
            return false;
        }
    }
    return true;
}

function indexOf(arr, val, comparer) {
    for (var i = 0, len = arr.length; i < len; ++i) {
        if ( i in arr && comparer(arr[i], val) ) {
            return i;
        }
    }
    return -1;
}

var tw = [[3, 0], [11, 0], [3, 14], [11, 14]];
alert( indexOf(tw, [3, 0], arraysIdentical) ); // Alerts 0

Upvotes: 14

ZER0
ZER0

Reputation: 25332

Because you're comparing two difference instance of array. Comparing objects returns true only if they're the same instance, it doesn't matter if they contain the same data.

In your case, you could use this approach:

var tw = [[3, 0], [11, 0], [3, 14], [11, 14]];

if (~tw.join(";").split(";").indexOf(String([3, 0]))) {
    // ...
}

Or something more ortodox like:

if (tw.filter(function(v) { return String(v) === String([3, 10]) })[0]) {
   // ...
}

Where the condition can be adjusted depends by the content of the arrays.

Upvotes: 2

robbrit
robbrit

Reputation: 17960

This is because $.inArray and indexOf both use a shallow comparison using ===.

Since the array you're passing is to indexOf not the exact same in memory as the one in your 2D array, === returns false. You'll need to do a deep comparison to find the array properly - from a quick glance at the jQuery docs, this is not available there.

Upvotes: 0

Gwyn Howell
Gwyn Howell

Reputation: 5424

Arrays are objects. [3, 0] does not equal [3, 0] as they are different objects. That is why your inArray fails.

Upvotes: 2

Related Questions