Skip to content

Instantly share code, notes, and snippets.

@calda
Created September 18, 2018 19:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save calda/15b1b8d3f2c8adaf9a213f83a8c0a9eb to your computer and use it in GitHub Desktop.
Save calda/15b1b8d3f2c8adaf9a213f83a8c0a9eb to your computer and use it in GitHub Desktop.
`sort` ergonomics
// MARK: Collection + Sort Imprvements
extension Collection {
// an equivalent set of mutating `sort(by:)` methods would also be made available.
func sorted<T: Comparable>(by value: (Element) throws -> T) rethrows -> [Element] {
return try self.sorted(by: { lhs, rhs in
return (try value(lhs)) < (try value(rhs))
})
}
func sorted(by sortDescriptors: [SortDescriptor<Element>]) -> [Element] {
return self.sorted(by: { lhs, rhs in
for sortDescriptor in sortDescriptors {
if sortDescriptor.orders(lhs, before: rhs) {
return true
} else if sortDescriptor.orders(rhs, before: lhs) {
return false
}
// Otherwise, the two items are equal.
// Fall-through to the next SortDescriptor.
}
// If we've exhausted the SortDescriptors, then we don't have
// enough information to determine the sort order.
return false
})
}
}
// MARK: SortDescriptor
public struct SortDescriptor<Element> {
private let inIncreasingOrder: (Element, Element) -> Bool
private init(inIncreasingOrder: @escaping (Element, Element) -> Bool) {
self.inIncreasingOrder = inIncreasingOrder
}
public init<Value: Comparable>(_ value: @escaping (Element) -> Value) {
self.inIncreasingOrder = { lhs, rhs in
value(lhs) < value(rhs)
}
}
public func orders(_ lhs: Element, before rhs: Element) -> Bool {
return inIncreasingOrder(lhs, rhs)
}
/// Returns a `SortDescriptor` based on the same property, but with a reversed sort order.
public var reversed: SortDescriptor<Element> {
return SortDescriptor(inIncreasingOrder: { lhs, rhs in
if self.inIncreasingOrder(lhs, rhs) {
return false
} else if self.inIncreasingOrder(rhs, lhs) {
return true
} else {
// This is the `orderedSame` / `==` case.
return false
}
})
}
}
// MARK: Examples
struct Person {
let name: String
let age: Int
}
let people = [
Person(name: "Bob", age: 34),
Person(name: "Alice", age: 34),
Person(name: "Eve", age: 30)]
people.sorted(by: { $0.age })
// instead of
people.sorted(by: { $0.age < $1.age })
people.sorted(by: [
SortDescriptor({ $0.age }),
SortDescriptor({ $0.name })])
// instead of
people.sorted(by: { lhs, rhs in
if lhs.age == rhs.age {
return lhs.name < rhs.name
} else {
return lhs.age < lhs.age
}
})
// @objc / Foundation:
//
// import Foundation
//
// (people as NSArray).sortedArray(using: [
// NSSortDescriptor(keyPath: \Person.age, ascending: true),
// NSSortDescriptor(keyPath: \Person.name, ascending: true)
// ]) as! [Person]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment