Create copy of multi-dimensional array, not reference - JavaScript
As you asked for performance, I guess you also would go with a non-generic solution. To copy a multi-dimensional array with a known number of levels, you should go with the easiest solution, some nested for-loops. For your two-dimensional array, it simply would look like this:
var len = arr.length,
copy = new Array(len); // boost in Safari
for (var i=0; i<len; ++i)
copy[i] = arr[i].slice(0);
To extend to higher-dimensional arrays, either use recursion or nested for loops!
The native slice
method is more efficient than a custom for loop, yet it does not create deep copies, so we can use it only at the lowest level.
I'm not sure how much better JSON.stringify
and JSON.parse
than encode
and decode
, but you could try:
JSON.parse(JSON.stringify(array));
Something else I found (although I'd modify it a little):
http://www.xenoveritas.org/blog/xeno/the-correct-way-to-clone-javascript-arrays
function deepCopy(obj) {
if (typeof obj == 'object') {
if (isArray(obj)) {
var l = obj.length;
var r = new Array(l);
for (var i = 0; i < l; i++) {
r[i] = deepCopy(obj[i]);
}
return r;
} else {
var r = {};
r.prototype = obj.prototype;
for (var k in obj) {
r[k] = deepCopy(obj[k]);
}
return r;
}
}
return obj;
}
Any recursive algorithm that doesn't visit the same node twice will be about as efficient as you get with javascript (at least in a browser) - in certain situations in other languages you might get away with copying chucks of memory, but javascript obviously doesn't have that ability.
I'd suggest finding someone who's already done it and using their implementation to make sure you get it right - it only needs to be defined once.
Since it sounds like you're dealing with an Array of Arrays to some unknown level of depth, but you only need to deal with them at one level deep at any given time, then it's going to be simple and fast to use .slice()
.
var newArray = [];
for (var i = 0; i < currentArray.length; i++)
newArray[i] = currentArray[i].slice();
Or using .map()
instead of the for
loop:
var newArray = currentArray.map(function(arr) {
return arr.slice();
});
So this iterates the current Array, and builds a new Array of shallow copies of the nested Arrays. Then when you go to the next level of depth, you'd do the same thing.
Of course if there's a mixture of Arrays and other data, you'll want to test what it is before you slice.