Created
September 18, 2018 19:39
-
-
Save calda/15b1b8d3f2c8adaf9a213f83a8c0a9eb to your computer and use it in GitHub Desktop.
`sort` ergonomics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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