4

I want to make a clone of multidimensional Array so that i can play arround with the clone array without affecting main Array.

I'm using following function to do so:

Array.prototype.clone = function () { 
   var newArray = new Array(this.length);
     for(var i=0; i < this.length; i++ ){
        newArray[i] = this[i];
   }
   return newArray;
};

But problem which is since it is using array prototype so it will clone my all array.so can any body tell me what is the best way of doing this.

Community
  • 1
  • 1
Abhimanyu
  • 4,752
  • 7
  • 33
  • 44

3 Answers3

10

vsync is correct, my first answer doesn't handle var a = [[1,2],[3,4]];
So here's an improved version

var a = [[1,2],[3,4]];
Array.prototype.clone = function() {
    var arr = this.slice(0);
    for( var i = 0; i < this.length; i++ ) {
        if( this[i].clone ) {
            //recursion
            arr[i] = this[i].clone();
        }
    }
    return arr;
}

var b = a.clone()

console.log(a);
console.log(b);

b[1][0] = 'a';

console.log(a);
console.log(b);

//[[1, 2], [3, 4]]
//[[1, 2], [3, 4]]
//[[1, 2], [3, 4]]
//[[1, 2], ["a", 4]]
meouw
  • 41,754
  • 10
  • 52
  • 69
  • The first answer didn't work properly for me but this one worked perfectly. Thanks! – Chris Porter May 26 '12 at 16:09
  • 2
    Thank you so much for posting this method here. I got another improvement for it: `if( this[i] && this[i].clone ) {` to support _sparse_ arrays (or whatever you call it when some values are null) – michael667 Apr 25 '13 at 21:37
5

You need to use recursion

var a = [1,2,[3,4,[5,6]]];

Array.prototype.clone = function() {
    var arr = [];
    for( var i = 0; i < this.length; i++ ) {
//      if( this[i].constructor == this.constructor ) {
        if( this[i].clone ) {
            //recursion
            arr[i] = this[i].clone();
            break;
        }
        arr[i] = this[i];
    }
    return arr;
}

var b = a.clone()

console.log(a);
console.log(b);

b[2][0] = 'a';

console.log(a);
console.log(b);

/*
[1, 2, [3, 4, [5, 6]]]
[1, 2, [3, 4, [5, 6]]]
[1, 2, [3, 4, [5, 6]]]
[1, 2, ["a", 4, [5, 6]]]
*/

Any other objects in the original array will be copied by reference though

meouw
  • 41,754
  • 10
  • 52
  • 69
  • You could check for the presence of a `clone` method on each object in the array, and call it to clone the object if present. This will handle the recursion of arrays and also allow any other objects with clone methods to be deep-copied as well. – Daniel Earwicker Feb 19 '10 at 08:26
  • 1
    it doesn't clone stuff like this properly: `var a = [[1,2],[3,4]];` – vsync May 21 '11 at 12:45
4

I found that this approach is better than meouw's :

var source = [
  [1, 2, {c:1}],
  [3, 4, [5, 'a']]
];

// Create a new method ontop of the "Array" primitive prototype:
Array.prototype.clone = function() {
  function isArr(elm) {
    return String(elm.constructor).match(/array/i) ? true : false;
  }

  function cloner(arr) {
    var arr2 = arr.slice(0),
        len = arr2.length;

    for (var i = 0; i < len; i++)
      if (isArr(arr2[i]))
        arr2[i] = cloner(arr2[i]);

    return arr2;
  }
  return cloner(this);
}

// Clone
var copy = source.clone();

// modify copy
copy[0][0] = 999;

console.dir(source);
console.dir('**************');
console.dir(copy);

Another method, which can only work on data sets which have primitives
as values (String, Numbers, Objects) :

var source = [
  [1,2, {a:1}],
  ["a", "b", ["c", 1]]
];

// clone "srouce" Array
var copy = JSON.parse(JSON.stringify(source));

// modyfy clone
copy[0][0] = 999;

// print both arrays
console.dir(copy)
console.log('***********')
console.dir(source)
vsync
  • 118,978
  • 58
  • 307
  • 400