Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@calda
Created July 20, 2018 00:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save calda/bd0458be229173d27f3143bb49cdee75 to your computer and use it in GitHub Desktop.
Save calda/bd0458be229173d27f3143bb49cdee75 to your computer and use it in GitHub Desktop.
SortDescriptors (July 18)
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
})
}
}
@AKoulabukhov
Copy link

Great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment