zomgistania

Main page | About | Articles | Previous Posts | Archives

Saturday, July 22, 2006

Comparing and copying arrays in JavaScript is a pain

Ever wanted to copy an array in JavaScript? Tried the simple var array2 = array1?
Yes, it doesn't work that way.

Apparently with arrays and objects, JS uses references just like C# and in case you want to make a copy of an array...


function CopyArray(a)
{
//Create a new array with the old ones length
var n = new Array(a.length);

//Just copy all the values from the old to the new
for(var i = 0; i < a.length; i++)
n[i] = a[i];

return n;
}

var array2 = CopyArray(array1);


You'll have to use something like that. Of course it gets way more complicated when dealing with jagged arrays, eg. arrays which have arrays in them. You'll have to write a recursive function or something the like of this:


function CopyArray(a)
{
//Create a new array with the old ones length
var n = new Array(a.length);

//Just copy all the values from the old to the new
for(var i = 0; i < a.length; i++)
{
//if the value in the old array is an object (array)
//call the CopyArray function recursively
if(typeof a[i] == 'object')
n[i] = CopyArray(a[i]);
else
n[i] = a[i];
}

return n;
}


With that you can create nice copies of arrays while still keeping them as array objects.


How about comparing arrays? Uh oh, if(a == b) doesn't work like expected!

Yet again we'll have to use a customized function


//Check if two arrays' contents are the same
//returns true if they are, otherwise false
Equals = function(a,b)
{
//Check if the arrays are undefined/null
if(!a || !b)
return false;

//first compare their lengths
if(a.length == b.length)
{
//go thru all the vars
for(var i = 0; i < a.length;i++)
{
//if the var is an array, we need to make a recursive check
//otherwise we'll just compare the values
if(typeof a[i] == 'object') {
if(!Equals(a[i],b[i]))
return false;
}
else if(a[i] != b[i])
return false;
}
return true;
}
else return false;
}

if(Equals(a,b)) { /* ... */ }


ookay!

You might notice that the usual JavaScript naming convention is that function names start with a small letter. I use capital letters just because I'm used to that from C# and it looks better to my eye.

9 Comments:

  • I always wondered about this. Thanks for the explanation!

    By Anonymous Anonymous, at 12:29 PM  

  • Easier solutions.

    To copy an array:
    var array1 = array2.slice();

    To compare them:
    if (array1.toString() == array2.toString()) alert("they're equal");

    By Anonymous Anonymous, at 10:21 PM  

  • and if order doesn't matter when comparing:
    if (array1.sort().toString() == array2.sort().toString())
    alert("they are equal unordered arrays");

    By Anonymous Anonymous, at 5:47 AM  

  • I haven't tried your method yet but I created my own and wanted to share it with someone.

    I need to compare objects that can contain other objects, strings, or arrays and I don't care about the order in which array values are listed.

    So here's what I have and it works well. Hope it helps someone or maybe someone can tell me how I could have done this an easier way.

    /**
    Compares two objects. The objects can contain other objects, strings, or arrays.
    It cannot determine the equality of function types. It has not been tested
    with DOM elements.
    **/
    compare: function(item1, item2) {
    var equals = false;
    var exit = false;

    try {
    if(this.isObject(item1)&&this.isObject(item2)) {
    if(this.isArray(item1)==false&&this.isArray(item2)==false) {
    for (var p1 in item1) {
    for(var p2 in item2) {
    if(item2[p1]) {
    if(this.isObject(item1[p1])==true&&this.isObject(item2[p2])==true) {
    equals = this.compare(item1[p1], item2[p2]);
    } else {
    if(p1==p2) {
    if(item1[p1]==item2[p2]) {
    equals = true;
    } else {
    exit = true;
    break;
    }
    }
    }
    }
    }
    if(exit==true) {
    break;
    }
    }
    } else {
    if(item1.length&&item2.length) {
    if(item1.length==item2.length) {
    for (p3 in item1) {
    for(p4 in item2) {
    if(item2[p3]) {
    if(this.isObject(item1[p3])==true&&this.isObject(item2[p4])==true) {
    equals = this.compare(item1[p3], item2[p4]);
    } else {
    if(p3==p4) {
    if(item1[p3]==item2[p4]) {
    equals = true;
    }
    } else {
    exit = true;
    break;
    }
    }
    }
    }
    if(exit==true) {
    break;
    }
    }
    } else {
    equals = false;
    }
    } else {
    equals = true;
    }
    }
    } else {
    if(item1==item2) {
    equals = true;
    }
    }
    }catch(ex) {
    equals = false;
    }

    return equals;
    },

    isObject: function(obj) {
    return typeof(obj)=='object';
    },

    isArray: function(obj) {
    if (obj.constructor.toString().indexOf("Array") == -1) {
    return false;
    } else {
    return true;
    }
    }

    By Anonymous Anonymous, at 11:00 AM  

  • to copy array
    var arrName = ["jack","jill"];

    var copy_of_arrName = eval(arrName.toString());

    similarly you can compare arrays too...

    By Anonymous Anonymous, at 1:57 PM  

  • >if (array1.toString() == >array2.toString()) alert("they're >equal");

    Wow!!
    So:
    array1 = ["a,b"];
    array2 = ["a","b"];

    and they are equal!

    incredible!

    This is an easier way to go WRONG.

    By Blogger Francesco, at 12:49 PM  

  • Copying an array is much simpler than that:

    array2 = array1.slice();

    By Blogger Ricardo Tomasi, at 12:10 AM  

  • Be careful about naming your functions with a Capital letter, because in JavaScript we normally start with a Capital letter when the function needs to be instantiated (ie a constructor function). This is because since in JavaScript there is no compile-time errors, the naming convention is only thing we have.

    By Blogger Andreas Grech, at 12:14 PM  

  • Thanks a lot.
    It's saves my time

    By Anonymous Anonymous, at 12:33 PM  

Post a Comment

<< Home