Created
July 20, 2018 00:58
-
-
Save calda/bd0458be229173d27f3143bb49cdee75 to your computer and use it in GitHub Desktop.
SortDescriptors (July 18)
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
public struct SortDescriptor<Element> { | |
private let keyPath: PartialKeyPath<Element> | |
private let comparator: (Any, Any) -> ComparisonResult | |
// For abitrary `Value` types, the consumer has to provide the entire Comparator | |
public init<Value>( | |
_ keyPath: KeyPath<Element, Value>, | |
using comparator: @escaping (Value, Value) -> ComparisonResult) | |
{ | |
self.keyPath = keyPath | |
self.comparator = { anyLhs, anyRhs in | |
// un-erase the (Any, Any) | |
guard let lhs = anyLhs as? Value, | |
let rhs = anyRhs as? Value else | |
{ | |
return .orderedSame // this should be impossible to hit with the API as-written | |
} | |
return comparator(lhs, rhs) | |
} | |
} | |
// For `Equatable` types, the consumer only has to provide us with the `Comparable` bit | |
public init<Value: Equatable>( | |
_ keyPath: KeyPath<Element, Value>, | |
using valuesAreInIncreasingOrder: @escaping (Value, Value) -> Bool) | |
{ | |
self.init(keyPath, using: { lhs, rhs -> ComparisonResult in | |
if lhs == rhs { | |
return .orderedSame | |
} else { | |
return valuesAreInIncreasingOrder(lhs, rhs) ? .orderedAscending : .orderedDescending | |
} | |
}) | |
} | |
// `Comparable` types have all of the pieces we need to build a comparator | |
public init<Value: Comparable>(_ keyPath: KeyPath<Element, Value>) { | |
self.init(keyPath, using: <) | |
} | |
// This initializer specifically lets us use methods like `String.caseInsensitiveCompare` | |
// in an ergonomic way. | |
public init<Value>( | |
_ keyPath: KeyPath<Element, Value>, | |
using curriedComparator: @escaping (Value) -> (Value) -> ComparisonResult) | |
{ | |
self.init(keyPath, using: { lhs, rhs -> ComparisonResult in | |
return curriedComparator(lhs)(rhs) | |
}) | |
} | |
/// Compares the provided elements using the provided KeyPath and comparison procedure | |
public func compareElements(_ lhs: Element, _ rhs: Element) -> ComparisonResult { | |
return comparator(lhs[keyPath: keyPath], rhs[keyPath: keyPath]) | |
} | |
} | |
// Sequence + Sorted by Descriptors | |
extension Sequence { | |
public func sorted(by descriptors: [SortDescriptor<Self.Element>]) -> [Self.Element] { | |
return self.sorted(by: { lhs, rhs in | |
for descriptor in descriptors { | |
let result = descriptor.compareElements(lhs, rhs) | |
if result != .orderedSame { | |
return (result == .orderedAscending) | |
} | |
} | |
return false | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great!