Last active
October 15, 2018 02:35
-
-
Save timvermeulen/46c58d28f5dc37ac3406280f2a0486e5 to your computer and use it in GitHub Desktop.
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
// Monoid | |
precedencegroup MonoidPrecedence { | |
associativity: left | |
} | |
infix operator <> : MonoidPrecedence | |
protocol Monoid { | |
static var empty: Self { get } | |
static func <> (lhs: Self, rhs: Self) -> Self | |
} | |
// SortDescriptor | |
struct SortDescriptor<Value> { | |
let isOrderedBefore: (Value, Value) -> Bool | |
} | |
prefix operator ~ | |
extension SortDescriptor { | |
init<T>(_ block: @escaping (Value) -> T, _ isOrderedBefore: @escaping (T, T) -> Bool) { | |
self.init { isOrderedBefore(block($1), block($0)) } | |
} | |
init<T: Comparable>(_ block: @escaping (Value) -> T) { | |
self.init(block, <) | |
} | |
static prefix func ~ (value: SortDescriptor) -> SortDescriptor { | |
return .init { value.isOrderedBefore($1, $0) } | |
} | |
} | |
extension SortDescriptor: Monoid { | |
static var empty: SortDescriptor<Value> { | |
return SortDescriptor { _, _ in false } | |
} | |
static func <> (lhs: SortDescriptor<Value>, rhs: SortDescriptor<Value>) -> SortDescriptor<Value> { | |
return SortDescriptor { lhs.isOrderedBefore($0, $1) ? true : lhs.isOrderedBefore($1, $0) ? false : rhs.isOrderedBefore($0, $1) } | |
} | |
} | |
extension Sequence { | |
func sorted(by descriptor: SortDescriptor<Element>) -> [Element] { | |
return sorted(by: descriptor.isOrderedBefore) | |
} | |
} | |
// KeyPaths | |
prefix operator ^ | |
prefix func ^ <Value, T: Comparable> (keyPath: KeyPath<Value, T>) -> SortDescriptor<Value> { | |
return .init(^keyPath) | |
} | |
extension KeyPath { | |
static prefix func ^ (keyPath: KeyPath) -> (Root) -> Value { | |
return { $0[keyPath: keyPath] } | |
} | |
} | |
// Example | |
import Foundation | |
struct Person { | |
let first: String | |
let last: String | |
let yearOfBirth: Int | |
} | |
let people = [ | |
Person(first: "Jo", last: "Smith", yearOfBirth: 1970), | |
Person(first: "Joanne", last: "Williams", yearOfBirth: 1985), | |
Person(first: "Annie", last: "Williams", yearOfBirth: 1985), | |
Person(first: "Robert", last: "Jones", yearOfBirth: 1990) | |
] | |
let firstName = SortDescriptor<Person> { $0.first } | |
let lastName = SortDescriptor(^\Person.last) { $0.localizedCaseInsensitiveCompare($1) == .orderedAscending } | |
let sorted = people.sorted(by: ^\.yearOfBirth <> firstName <> ~lastName) | |
print(sorted.map(^\.first)) // ["Robert", "Joanne", "Annie", "Jo"] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment