Wie können Sie ein Array sortieren, ohne das ursprüngliche Array zu mutieren?

229

Angenommen, ich wollte eine Sortierfunktion, die eine sortierte Kopie des eingegebenen Arrays zurückgibt. Ich habe das naiv versucht

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

und ich habe es damit getestet, was zeigt, dass meine sortMethode das Array mutiert.

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"

Ich habe diesen Ansatz auch ausprobiert

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

aber es funktioniert überhaupt nicht.

Gibt es einen einfachen Weg, um dies zu umgehen, vorzugsweise einen Weg, bei dem nicht mein eigener Sortieralgorithmus von Hand gerollt oder jedes Element des Arrays in ein neues kopiert werden muss?

Peter Olson
quelle
1
Erstellen Sie eine tiefe Kopie des Arrays und sortieren Sie sie stattdessen.
evanmcdonnal
1
@evanmcdonnal Eine flache Kopie ist möglicherweise gut genug, wenn nur eine Neuordnung und nicht ein Duplikat jedes Elements im Array gewünscht wird.
Kekoa
.sorterfordert, dass der thisWert das Array ist, damit das letzte Snippet funktioniert .sort.call(arr)(obwohl es Ihr Problem nicht löst).
Pimvdb
@ Kekoa Ja das ist ein guter Punkt. Es ist nicht erforderlich, mehr Speicher zu verbrauchen, wenn Sie nur die Reihenfolge der Elemente und nicht die Elemente selbst ändern möchten.
evanmcdonnal
Die Methode von zzzzBov funktioniert wie ein Zauber! stackoverflow.com/a/9592774/7011860
Samet M.

Antworten:

221

Kopieren Sie einfach das Array. Dafür gibt es viele Möglichkeiten:

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

// Or:
return Array.prototype.slice.call(arr).sort(); // For array-like objects
Rob W.
quelle
2
Wird dies eine tiefe Kopie machen, dh werden auch verschachtelte Objekte und Arrays kopiert?
Peter Olson
2
Gibt es einen Vorteil bei der Verwendung von concatover say slice(0)oder sind sie alle ziemlich gleich?
JaredPar
3
@ PeterOlson Nein, es ist eine flache Kopie. Wenn Sie wirklich eine tiefe Kopie wünschen, verwenden Sie die Suchfunktion von Stack Overflow, um vorhandene hervorragende Antworten darauf zu finden.
Rob W
11
Slice wird jetzt als deutlich schneller gemeldet
Zander Brown
3
warum Array.prototype.slice.call(arr).sort();statt arr.slice().sort();?
Olivier Boissé
60

Versuche Folgendes

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

Der slice(0)Ausdruck erstellt eine Kopie des Arrays ab Element 0.

JaredPar
quelle
32

Sie können Slice ohne Argumente verwenden, um ein Array zu kopieren:

var foo,
    bar;
foo = [3,1,2];
bar = foo.slice().sort();
zzzzBov
quelle
Diese Antwort ist fantastisch! Ich bin überrascht, dass JavaScript eine Mutation in diesem Ausmaß zulässt. Scheint falsch. Danke noch einmal.
11

Sie können dies auch tun

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

Auf diese Weise wird d nicht mutiert.

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

//Use it like this
x = [20, 10, 100]
console.log(sorted(x))
Aditya Agarwal
quelle
Diese Antwort ist nett
Leasye
1

Jeder, der eine tiefe Kopie erstellen möchte (z. B. wenn Ihr Array Objekte enthält), kann Folgendes verwenden:

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

Dann können Sie sortieren, arrCopyohne zu ändern arr.

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

Bitte beachten Sie: Dies kann bei sehr großen Arrays langsam sein.

Hamada
quelle
Dies funktioniert -statt >in Ihrem zweiten Beispiel.
Pootzko
0

Ich verwende Object.assign () für die meisten meiner Kopien:

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

Nachdem ich die OP-Kommentare durchgesehen hatte, recherchierte ich ein bisschen tiefgreifendes Kopieren und stellte fest, dass Object.assign nicht nur eine flache Kopie ausführt, sondern auch nur aufzählbare und eigene Eigenschaften auswählt (wie in diesem Beitrag beantwortet ).

Sun Lee
quelle