¿Cómo se puede ordenar una matriz sin mutar la matriz original?

230

Supongamos que quisiera una función de clasificación que devuelva una copia ordenada de la matriz ingresada. Intenté ingenuamente esto

function sort(arr) {
  return arr.sort();
}

y lo probé con esto, lo que muestra que mi sortmétodo está mutando la matriz.

var a = [2,3,7,5,3,7,1,3,4];
sort(a);
alert(a);  //alerts "1,2,3,3,3,4,5,7,7"

También probé este enfoque

function sort(arr) {
  return Array.prototype.sort(arr);
}

Pero no funciona en absoluto.

¿Existe una forma directa de evitar esto, preferiblemente una forma que no requiera mover manualmente mi propio algoritmo de clasificación o copiar cada elemento de la matriz en uno nuevo?

Peter Olson
fuente
1
cree una copia profunda de la matriz y ordénela en su lugar.
evanmcdonnal
1
@evanmcdonnal Una copia superficial podría ser lo suficientemente buena si todo lo que se desea es un reordenamiento y no un duplicado de cada elemento de la matriz.
Kekoa
.sortrequiere que el thisvalor sea la matriz, por lo que para que el último fragmento funcione funcionaría .sort.call(arr)(aunque no resuelve su problema).
pimvdb
@Kekoa Sí, ese es un buen punto. No es necesario consumir más memoria si solo va a cambiar el orden de los elementos y no los elementos en sí.
evanmcdonnal
¡El método de zzzzBov funciona a las mil maravillas! stackoverflow.com/a/9592774/7011860
Samet M.

Respuestas:

223

Simplemente copie la matriz. Hay muchas formas de hacer eso:

function sort(arr) {
  return arr.concat().sort();
}

// Or:
return Array.prototype.slice.call(arr).sort(); // For array-like objects
Rob W
fuente
2
¿Esto hará una copia profunda, es decir, también se copiarán objetos anidados y matrices?
Peter Olson
2
¿Hay alguna ventaja en usar concatsobre say slice(0)o son todos prácticamente iguales?
JaredPar
3
@PeterOlson No, es una copia superficial. Si realmente desea una copia profunda, use la función de búsqueda en Stack Overflow para encontrar excelentes respuestas existentes para eso.
Rob W
11
Slice ahora se informa como notablemente más rápido
Zander Brown,
3
¿Por qué en Array.prototype.slice.call(arr).sort();lugar de arr.slice().sort();?
Olivier Boissé
61

Intenta lo siguiente

function sortCopy(arr) { 
  return arr.slice(0).sort();
}

La slice(0)expresión crea una copia de la matriz comenzando en el elemento 0.

JaredPar
fuente
32

Puede usar el segmento sin argumentos para copiar una matriz:

var foo,
    bar;
foo = [3,1,2];
bar = foo.slice().sort();
zzzzBov
fuente
¡Esta respuesta es asombrosa! Me sorprende que JavaScript permita la mutación en este grado. Parece mal Gracias de nuevo.
12

También puedes hacer esto

d = [20, 30, 10]
e = Array.from(d)
e.sort()

De esta manera, d no será mutado.

function sorted(arr) {
  temp = Array.from(arr)
  return temp.sort()
}

//Use it like this
x = [20, 10, 100]
console.log(sorted(x))
Aditya Agarwal
fuente
Esta respuesta es buena
Leasye
1

Cualquier persona que quiera hacer una copia profunda (por ejemplo, si su matriz contiene objetos) puede usar:

let arrCopy = JSON.parse(JSON.stringify(arr))

Entonces puedes ordenar arrCopysin cambiar arr.

arrCopy.sort((obj1, obj2) => obj1.id > obj2.id)

Tenga en cuenta: esto puede ser lento para matrices muy grandes.

Hamada
fuente
Esto funcionará en -lugar de >en su segundo ejemplo.
Pootzko
0

Yo uso Object.assign () para la mayoría de mis copias:

var copyArray = Object.assign([], originalArray).sort();

Sin embargo, después de mirar los comentarios de OP, investigué un poco de copia profunda y resultó que Object.assign no solo realiza una copia superficial, sino que también selecciona propiedades enumerables y propias (como se respondió en esta publicación ).

Sun Lee
fuente