I want to create a generic function to sort an array of classes based on a property passed.
For example, I have these classes
public class Car {
Expanding on @MartinR answer to allow increasing (<) or decreasing (>) sort:
extension MutableCollection where Self: RandomAccessCollection {
mutating func sort(_ keyPath: KeyPath, by areInIncreasingOrder: ((T, T) -> Bool) = (<)) {
sort(by: { areInIncreasingOrder($0[keyPath: keyPath], $1[keyPath: keyPath]) })
}
}
extension Sequence {
func sorted(_ keyPath: KeyPath, by areInIncreasingOrder: ((T,T)-> Bool) = (<)) -> [Element] {
sorted(by: { areInIncreasingOrder($0[keyPath: keyPath], $1[keyPath: keyPath]) })
}
}
people.sorted(\.age)
people.sorted(\.age, by: >)
cars.sorted(\.manufacturer)
cars.sorted(\.manufacturer, by: >)
edit/update:
To suport sorting a custom object by an optional property that conforms to Comparable protocol:
extension MutableCollection where Self: RandomAccessCollection {
mutating func sort(_ keyPath: KeyPath>, by areInIncreasingOrder: ((T, T) -> Bool) = (<)) {
sort(by: {
switch ($0[keyPath: keyPath], $1[keyPath: keyPath]) {
case let (lhs?, rhs?): return areInIncreasingOrder(lhs, rhs)
case (.none, _): return false
case (_, .none): return true
}
})
}
}
extension Sequence {
func sorted(_ keyPath: KeyPath>, by areInIncreasingOrder: ((T,T)-> Bool) = (<)) -> [Element] {
sorted(by: {
switch ($0[keyPath: keyPath], $1[keyPath: keyPath]) {
case let (lhs?, rhs?): return areInIncreasingOrder(lhs, rhs)
case (.none, _): return false
case (_, .none): return true
}
})
}
}
Usage:
array.sort(\.optionalStringProperty) {
$0.localizedStandardCompare($1) == .orderedAscending
}
print(array)