HOWTO · Rust
Sortieren Sie einen Vektor in Rust
Die Funktionen sort_by() und sort() beziehen sich auf den Vektor und geben ihn sortiert zurück. Die Werte sind standardmäßig aufsteigend sortiert.
Auf dieser Seite
Um einen Vektor in Rust aufsteigend zu sortieren, rufen Sie sort() für einen veränderlichen Vektor auf. Die Methode sortiert den Vektor direkt und verwendet die natürliche Ordnung seiner Elemente. Mit sort_by() können Sie ausgewählte Felder vergleichen oder eine andere Ordnung festlegen. Beide Methoden gehören zur Rust-Standardbibliothek.
Direktes Sortieren mit sort()
sort() ist die passende Wahl, wenn der Elementtyp eine natürliche totale Ordnung besitzt. Der Vektor muss veränderlich sein, da beim Sortieren seine Elemente umgeordnet werden. Der Elementtyp muss das Trait Ord implementieren; Ganzzahlen und Zeichenketten erfüllen diese Voraussetzung, Gleitkommatypen dagegen nicht.
Führen Sie dieses Beispiel aus:
fn main() {
let mut numbers = vec![5, 3, 8, 1, 2];
numbers.sort();
println!("{:?}", numbers);
}
Nach dem Aufruf enthält numbers dieselben Werte in aufsteigender Reihenfolge. Die Methode sortiert den vorhandenen Vektor, statt einen neu sortierten Vektor zurückzugeben. Verwenden Sie daher eine veränderliche Bindung, wenn Sie das Ergebnis weiterverwenden möchten.
Bei einem Vektor aus Zeichenketten verwendet sort() ebenfalls die natürliche Ordnung des Typs. Für eine absteigende Sortierung können Sie sort_by() verwenden und den Vergleich umkehren, zum Beispiel mit |a, b| b.cmp(a). Wählen Sie die Ordnung bewusst, wenn die natürliche Ordnung nicht dazu passt, wie Ihre Anwendung Werte darstellt oder gruppiert.
Benutzerdefinierte Sortierung mit sort_by()
sort_by() erwartet eine Comparator-Closure. Rust übergibt der Closure zwei Elemente; sie gibt einen Wert des Typs Ordering zurück: Less, Equal oder Greater. Dabei werden zwei Elemente miteinander verglichen. Die Closure liefert also keinen einzelnen Schlüssel für jedes Element. Bei Werten, die Ord implementieren, ist die Methode cmp() eine praktische Möglichkeit, das Vergleichsergebnis zu erzeugen.
Dieses Beispiel sortiert Tupel anhand ihres zweiten Feldes, vom kleinsten zum größten Wert:
fn main() {
let mut pairs = vec![(1, 3), (2, 1), (3, 2)];
pairs.sort_by(|a, b| a.1.cmp(&b.1));
println!("{:?}", pairs);
}
Die Closure vergleicht a.1 mit b.1; sie verändert die Tupelwerte nicht. Um nach mehreren Feldern zu sortieren, vergleichen Sie zuerst das wichtigste Feld und entscheiden bei Gleichstand anhand eines weiteren Vergleichs. Der Comparator sollte konsistent sein und für dasselbe Wertepaar stets eine stabile Ordnung ausdrücken. sort_by() verändert den Vektor ebenfalls direkt. Daher muss auch hier die Bindung veränderlich sein.
Gleitkommazahlen sicher sortieren
Die Typen f32 und f64 in Rust implementieren PartialOrd, aber nicht Ord. Die meisten endlichen Werte lassen sich vergleichen, doch Vergleiche mit NaN ergeben keine Ordnung. Deshalb lässt sich sort() nicht direkt für einen Vektor aus Gleitkommazahlen aufrufen. Außerdem kann das Entpacken des Ergebnisses von partial_cmp() zu einer Panik führen, wenn ein Wert NaN ist.
Wenn Sie für Gleitkommazahlen die totale Ordnung von Rust verwenden möchten, setzen Sie total_cmp() im Comparator ein. Diese Methode ordnet auch NaN ein und unterscheidet negative von positiven Nullwerten. Das folgende eigenständige Beispiel enthält ausdrücklich einen NaN-Wert, damit die gewählte Regel klar ist:
fn main() {
let mut values = vec![3.5_f64, f64::NAN, -1.0, 2.0];
values.sort_by(f64::total_cmp);
println!("{:?}", values);
}
total_cmp() eignet sich, wenn jeder Gleitkommawert an einer deterministischen Ordnung teilnehmen soll. Wenn Ihre Anwendung stattdessen alle NaN-Werte ans Ende setzen oder sie zurückweisen soll, legen Sie diese Regel ausdrücklich im Comparator fest oder prüfen Sie die Daten vor dem Sortieren. Eine totale Ordnung ist eine Vergleichsregel; sie entscheidet nicht, welche Regel für Ihre Daten die richtige ist.