As you know, in javascript when a variable is assigned another ( a=b
), in case the source contains an object, a copy is not made, but a reference (a pointer), so that modifying the value is reflected in both.
For example:
var matriz = ["a1","a2"];
var copiaMatriz = matriz;
matriz[0]="x";
copiaMatriz[1]="y";
console.log(matriz,copiaMatriz);
The system that I currently use to solve this problem is by going through the array recursively and assigning the values as they are not other arrays (if the values are other types of objects that are not
Array
(for example functions), they will continue to be references, which no problem for me). Example with a 3-dimensional array:
var matriz =["a0" , "a1" , [
"b0", "b1", [
"c0", "c1"]
]
];
function copiaMatriz(matriz){
var copia=[];
matriz.forEach(function(valor){
if (Array.isArray(valor)) copia.push(copiaMatriz(valor));
else copia.push(valor);
});
return copia;
};
var matrizCopia = copiaMatriz(matriz);
matriz[2][2][0]="X";
matrizCopia[2][2][1]="Y";
console.log(matriz[2][2][0],matriz[2][2][1]);
console.log(matrizCopia[2][2][0],matrizCopia[2][2][1]);
I am quite surprised that in JavaScript the object
Array
does not already have a method to make a copy of the array, or another faster system, I have the feeling that it should be simpler and that I am complicating my life. My question is: Is there a method to make a copy of a multidimensional array that is faster than my current function? (ie run one level down using some object method
Array
or "trick" that you don't know about). P.S. Obviously I'm looking for a system that works on any matrix of any dimension.
EDIT
I have found that using methods of the object
JSON
can make a copy of a multidimensional array, but testing turns out to be almost the same or slower than the recursive copy. (Depends on the browser and the state of the cache, sometimes it is faster, but not much.) Example copying a 100x100x100 matrix 10 times.
var valores=100; // Array de valores x valores x valores
var matriz =[];
for (let i=0; i<valores; i++){
matriz[i]=[];
for (let j=0; j<valores; j++){
matriz[i][j]=[];
for (k=0; k<valores; k++){
matriz[i][j][k]=Math.floor(Math.random()*100);
}
}
}
var copias=10;
var matrizCopia=[];
var inicio=Date.now();
for (i=0; i<copias; i++){
matrizCopia=copiaMatriz(matriz);
}
console.log("Funcion matrizCopiar: "+(Date.now()-inicio)+"ms.");
var matrizCopia2=[];
var inicio=Date.now();
for (i=0; i<copias; i++){
matrizCopia2=copiaMatriz2(matriz);
}
console.log("Funcion matrizCopiar2: "+(Date.now()-inicio)+"ms.");
console.log("Comprobando que realiza copias y no referencias");
matriz[0][0][0]="a";
matrizCopia[0][0][1]="b";
matrizCopia2[0][0][2]="c";
console.log(matriz[0][0][0],matrizCopia[0][0][0],matrizCopia2[0][0][0]);
console.log(matriz[0][0][1],matrizCopia[0][0][1],matrizCopia2[0][0][1]);
console.log(matriz[0][0][2],matrizCopia[0][0][2],matrizCopia2[0][0][2]);
function copiaMatriz(matriz){
var copia=[];
matriz.forEach(function(valor){
if (Array.isArray(valor)) copia.push(copiaMatriz(valor));
else copia.push(valor);
});
return copia;
};
function copiaMatriz2(matriz){
return JSON.parse(JSON.stringify(matriz));
}
No, there is no default method to do that in the core. I would recommend you to use the Lodash library https://lodash.com/docs/4.17.15#cloneDeep . It has a very well optimized deep cloning method
cloneDeep
that allows you to customize with a callback. The signature is_.cloneDeepWith(value, [customizer])
.