javascript indexOf not working as expected with array

baixiwei picture baixiwei · Jan 8, 2013 · Viewed 48.8k times · Source

I am getting -1 from myarray.indexOf(element) even when element appears to be in myarray.

Here's some code snippets:

function createChangeRecord( old_array, new_array ) {
    var nds = new_array.slice(0,new_array.length);
    var el, idx;
    if (...) {
        ...
    } else if ( old_array.length==new_array.length ) {
        for ( var i=0; i<old_array.length; i++ ) {
            el = old_array[i];
            idx = nds.indexOf(el);
            if ( idx!=(-1) ) {
                ...
            } else {
                var a = "el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + nds.indexOf(el);
                alert( a );
                ...
            }
        }
        ...
    }
    ...
}

The alert shows me that nds does indeed contain el but the alert should only fire when idx==-1, which should only be true when nds does not contain el.

I know I haven't given enough information to determine the specific issue in my case, but maybe someone can tell me some general reasons which might cause this behavior?

Responses to a similar question suggested using jQuery inArray() instead of indexOf, but I want to know why indexOf doesn't work. Others suggested that indexOf is for strings, not arrays, but that's not true from the online docs I can find.

Answer

Ajeet Shah picture Ajeet Shah · Oct 20, 2013

Use

nds.indexOf(parseInt(el,10)) 

where nds is an array and el is a number (or supposed to be a number)

Edit:

From msdn:

JavaScript is a loosely typed language, which means you do not declare the data types of variables explicitly. In many cases JavaScript performs conversions automatically when they are needed. For example, if you add a number to an item that consists of text (a string), the number is converted to text.

And I guess such conversion was the reason of indexOf returning -1 because one of your array contained number and other contained string.

For example:

old_array = ["10", "20", "30"];
new_array = [10, 20, 30];

Below is my attempt to answer your questions:

Why indexOf() does not work?

It does work and I guess it worked in your case too. It returned -1 when el string, e.g "100", was not found in an array of numbers, e.g. nds=[100,200] which is true. Because "100" string is not same as 100 number.

Does indexOf() work with strings, array, etc?

Yes, indexOf() works with array (of number, string, or any object), as well as with string. But you have to make sure to check with same types.

What does parseInt() do?

To avoid unintended comparison of a number with a string, we can use parseInt(), for example parseInt("123", 10) returns the number 123.

The second argument 10 is called radix. A number (from 2 to 36) that represents the numeral system to be used.

Summary:

> "javascript is awesome".indexOf('v')
2
> [10, 20, 30].indexOf("20")
-1
> [10, 20, 30].indexOf(20)
1
> [10, 20, 30].indexOf( parseInt("20", 10) ) 
1
> typeof (100)
number
> typeof ("100")
string
> typeof( parseInt( "100", 10))
number
> parseInt( "100", 10)
100
> parseInt("100", 2)
4
> parseInt(11.3, 10)
11
> parseInt(11.3, 2)
3
> [10.3, 11.3, 12.3, 11].indexOf( parseInt(11.3, 10) )
3

To see all of above in action:

check the below code snippet but be aware of alert(); and console.log(); when you run it.

function createChangeRecord( old_array, new_array ) {

    var nds = new_array.slice( 0, new_array.length ); // this seems to be redundant
    var el, idx, msg;
    
    if ( old_array.length == new_array.length ) {
        for ( var i=0; i<old_array.length; i++ ) {

            el = old_array[i];
            idx = nds.indexOf(el);

            if ( idx != -1 ) {
                msg = "Found: el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + idx + "\n typeof el: " + (typeof el) + "; typepf nds[" + i + "]: " + (typeof nds[i]);
            } else {
                msg = "Not Found: el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + idx + "\n typeof el: " + (typeof el) + "; typepf nds[" + i + "]: " + (typeof nds[i]);
            }

            console.log( msg );
            alert( msg );
        }
    }
    else {
        var err = 'Array lengths are not same';
        console.log( err );
        alert( err );
    }
}

// this will work
var old_array_g = [ 10, 20 ];
var new_array_g = [ 10, 20 ];
createChangeRecord( old_array_g, new_array_g );

// this will not work
var old_array_g = [ "10", "20" ];
var new_array_g = [ 10, 20 ];
createChangeRecord( old_array_g, new_array_g );

// Yes: indesOf works with strings too

var withStrings = "'javascript is awesome'.indexOf('v'): " + "javascript is awesome".indexOf('v');
console.log( withStrings );
alert( withStrings );


// parseInt() returns a number or say integer
var usingParse = "typeof(123): " + typeof( 123 ) + "; typeof( parseInt('123', 10) ): " + typeof ( parseInt('123', 10) ) + "; typeof ('123'): " + typeof('123');
console.log( usingParse );
alert( usingParse );

// parseInt() with base 2
var parseBase2 = "parseInt( '100', 2 ): " + parseInt('100', 2) + "; parseInt( '100' , 10): " + parseInt('100', 10);
console.log( parseBase2 );
alert( parseBase2 );