Wie man ein Objektarray nach Eigenschaft in Swift sortiert: Ein Blick unter die Haube
Hallo, Kollege! Wenn du jemals eine App in Swift geschrieben hast, die eine Liste von Benutzern, Produkten oder Aufgaben anzeigt, bist du sicherlich auf die Notwendigkeit gestoßen, diese Daten zu sortieren. Die Frage „How to sort an array of custom objects by property value?“ ist eine der beliebtesten auf Stack Overflow. Und das aus gutem Grund: Auf den ersten Blick scheint alles einfach, aber wenn man tiefer gräbt, eröffnen sich ganze Ebenen von Möglichkeiten.
Heute geben wir nicht nur eine fertige Antwort. Wir werden analysieren, wie die Sortierung unter der Haube von Swift funktioniert, welche Mechanismen beteiligt sind und wie man nicht nur funktionierenden, sondern effizienten und eleganten Code schreibt. Los geht's!
Was ist die Sortierung eines Objektarrays in Swift?
Stell dir vor: Du hast ein Array von User-Objekten. Jeder Benutzer hat einen Namen, ein Alter und eine Bewertung. Du musst sie auf dem Bildschirm anzeigen, sortiert nach Alter (vom jüngsten zum ältesten).
In Swift wird dies mit den integrierten Methoden sort() (sortiert das Array direkt) und sorted() (gibt ein neues sortiertes Array zurück) erledigt. Beide akzeptieren ein Closure, das die Reihenfolge bestimmt.
struct User { let name: String let age: Int let rating: Double}
let users = [ User(name: "Anna", age: 25, rating: 4.5), User(name: "Boris", age: 30, rating: 3.8), User(name: "Vika", age: 22, rating: 4.9)]
// Sortierung nach Alter (aufsteigend)let sortedByAge = users.sorted { $0.age < $1.age }print(sortedByAge.map { $0.name }) // ["Vika", "Anna", "Boris"]Das war's. Aber lass uns genauer betrachten, was hier eigentlich passiert.
Wie funktioniert sort() unter der Haube: Algorithmen und Closures
Die Methode sort() in Swift verwendet den hybriden Algorithmus TimSort (benannt nach Tim Peters). Dies ist ein adaptiver, stabiler Sortieralgorithmus, der Mergesort und Insertionsort kombiniert. Er ist besonders effizient bei teilweise sortierten Daten – hallo, Nachrichtenfeeds und Aufgabenlisten!
Das Closure, das du übergibst, ist ein Sortierprädikat: eine Funktion, die zwei Elemente nimmt und true zurückgibt, wenn das erste vor dem zweiten stehen soll. Swift ruft dieses Closure wiederholt auf, um Elementpaare zu vergleichen.
Wichtig: Wenn deine Objekte dem Protokoll Comparable entsprechen, kannst du ganz auf ein Closure verzichten:
struct User: Comparable { let name: String let age: Int static func < (lhs: User, rhs: User) -> Bool { return lhs.age < rhs.age }}
let sortedUsers = users.sorted() // jetzt ganz einfachWas aber, wenn du zur Laufzeit nach verschiedenen Eigenschaften sortieren musst? Hier kommen Schlüsselpfade (KeyPath) zur Hilfe.
Sortierung mit KeyPath: Eleganz und Flexibilität
Seit Swift 4 haben wir KeyPath. Dies ist eine typsichere Möglichkeit, auf eine Eigenschaft eines Objekts zu verweisen. Durch die Kombination von KeyPath mit Closures können wir eine universelle Sortierfunktion schreiben:
extension Array { mutating func sort<T: Comparable>(by keyPath: KeyPath<Element, T>, ascending: Bool = true) { sort { ascending ? $0[keyPath: keyPath] < $1[keyPath: keyPath] : $0[keyPath: keyPath] > $1[keyPath: keyPath] } } func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>, ascending: Bool = true) -> [Element] { return sorted { ascending ? $0[keyPath: keyPath] < $1[keyPath: keyPath] : $0[keyPath: keyPath] > $1[keyPath: keyPath] } }}
// Verwendung:users.sort(by: \\.age) // nach Alter (aufsteigend)let sortedByRating = users.sorted(by: \\.rating, ascending: false) // nach Bewertung (absteigend)Wunderschön, oder? Typsicherheit