9

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.

2

6 Answers 6

14

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
Sign up to request clarification or add additional context in comments.

2 Comments

<deleted my spam>, see this updated example (the other jsFiddle was wrong) of why you should use if(i in arr&&comparer(arr[i], val))
@ajax333221: Ahhhh, I thought you were suggesting using for...in. Sorry. Yes, that is definitely an improvement, although it makes no difference for the case of this particular question and I'd argue that explicitly setting an array property to undefined is asking for trouble. I'll update my answer.
2

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

Comments

2

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.

Comments

2

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

1 Comment

I spend hours figuring out that NaN!==NaN is true, and typeof null is "object"
0

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.

Comments

0

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;
}

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.