Come è possibile ordinare un array senza mutare l'array originale?


230

Supponiamo che volessi una funzione di ordinamento che restituisca una copia ordinata dell'array immesso. L'ho provato ingenuamente

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

e l'ho provato con questo, il che dimostra che il mio sortmetodo sta mutando l'array.

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"

Ho anche provato questo approccio

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

ma non funziona affatto.

Esiste un modo semplice per aggirare questo, preferibilmente un modo che non richiede il roll-hand del mio algoritmo di ordinamento o la copia di ogni elemento dell'array in uno nuovo?


1
creare una copia profonda dell'array e ordinarlo invece.
evanmcdonnal,

1
@evanmcdonnal Una copia superficiale potrebbe essere abbastanza buona se tutto ciò che si desidera è un riordino e non un duplicato di ogni elemento dell'array.
Kekoa

.sortrichiede che il thisvalore sia l'array, quindi per far funzionare l'ultimo snippet .sort.call(arr)(anche se non risolve il problema).
pimvdb,

@Kekoa Sì, questo è un buon punto. Non è necessario consumare più memoria se si desidera modificare l'ordine degli elementi e non gli elementi stessi.
evanmcdonnal,

Il metodo di zzzzBov funziona come un incantesimo! stackoverflow.com/a/9592774/7011860
Samet M.

Risposte:


222

Basta copiare l'array. Ci sono molti modi per farlo:

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

// Or:
return Array.prototype.slice.call(arr).sort(); // For array-like objects

2
Questo eseguirà una copia profonda, ovvero verranno copiati anche oggetti e matrici nidificati?
Peter Olson,

2
C'è qualche vantaggio nell'usare concatover say slice(0)o sono praticamente tutti uguali?
JaredPar

3
@PeterOlson No, è una copia superficiale. Se vuoi davvero una copia profonda, usa la funzione di ricerca su Stack Overflow per trovare le risposte eccellenti esistenti per questo.
Rob W

11
Slice è ora segnalato come molto più veloce
Zander Brown,

3
perché Array.prototype.slice.call(arr).sort();invece di arr.slice().sort();?
Olivier Boissé il


61

Prova quanto segue

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

L' slice(0)espressione crea una copia dell'array a partire dall'elemento 0.


32

È possibile utilizzare slice senza argomenti per copiare un array:

var foo,
    bar;
foo = [3,1,2];
bar = foo.slice().sort();

Questa risposta è fantastica! Sono sorpreso che JavaScript permetta la mutazione a questo livello. Sembra sbagliato Grazie ancora.

12

Puoi anche farlo

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

In questo modo d non verrà mutato.

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

//Use it like this
x = [20, 10, 100]
console.log(sorted(x))

Questa risposta è buona
Leasye il

1

Chiunque desideri eseguire una copia profonda (ad esempio se l'array contiene oggetti) può utilizzare:

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

Quindi puoi ordinare arrCopysenza cambiare arr.

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

Nota: questo può essere lento per array molto grandi.


Funzionerà con -anziché >nel secondo esempio.
pootzko,

0

Uso Object.assign () per la maggior parte delle mie copie:

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

Tuttavia, dopo aver esaminato i commenti di OP, ho studiato un po 'di copia approfondita e ho scoperto che Object.assign non solo esegue una copia superficiale, ma seleziona anche solo le proprietà enumerabili e proprie (come indicato in questo post ).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.