[英]Dynamically passing closure with keypaths to a sorting function
我有這種方法用於基於 object 屬性進行排序:
extension Sequence {
mutating func sorted(
by predicates: [(Element, Element) -> Bool]
) -> [Element] {
return sorted(by:) { lhs, rhs in
for predicate in predicates {
if predicate(lhs, rhs) { return true }
if predicate(rhs, lhs) { return false }
}
return false
}
}
}
我可以像這樣在MyClass
類型的myArray
上使用它:
myArray.sorted(by: [{$0.propertyA > $1.propertyA}, {$0.propertyB > $1.propertyB}, {$0.propertyC < $1.propertyC}])
但我想動態構建這些謂詞,以便未預定義用於排序的屬性。
我想我應該使用 keyPaths (存儲類似KeyPath<MyModel, MyComparableType>
的東西,但我沒有運氣。
我將如何傳遞正確的運算符(小於,大於)以及我想用於排序的屬性?
您可以簡單地傳遞一個謂詞以從序列元素中返回一個可比較的屬性,並通過另一個謂詞來檢查兩個元素是否都在增加其他元素:
extension Sequence {
public func sorted<T: Comparable>(_ predicate: (Element) -> T, by areInIncreasingOrder: (T, T) -> Bool) -> [Element] {
sorted {
areInIncreasingOrder(predicate($0), predicate($1))
}
}
}
要支持多個標准(二級和三級),您只需向您的方法添加更多通用類型:
extension Sequence {
public func sorted<T: Comparable, U: Comparable>(_ primary: ((Element) -> T, (T, T) -> Bool), _ secondary: ((Element) -> U, (U, U) -> Bool)) -> [Element] {
sorted {
let lhs = primary.0($0)
let rhs = primary.0($1)
guard lhs == rhs else {
return primary.1(lhs, rhs)
}
return secondary.1(secondary.0($0), secondary.0($1))
}
}
public func sorted<T: Comparable, U: Comparable, V: Comparable>(_ primary: ((Element) -> T, (T, T) -> Bool), _ secondary: ((Element) -> U, (U, U) -> Bool), _ tertiary: ((Element) -> V, (V, V) -> Bool)) -> [Element] {
sorted {
let lhs1 = primary.0($0)
let rhs1 = primary.0($1)
guard lhs1 == rhs1 else {
return primary.1(lhs1, rhs1)
}
let lhs2 = secondary.0($0)
let rhs2 = secondary.0($1)
guard lhs2 == rhs2 else {
return secondary.1(lhs2, rhs2)
}
return tertiary.1(tertiary.0($0), tertiary.0($1))
}
}
}
現在,如果您想創建這些方法的變異版本,您需要擴展 MutableCollection 並將 Self 約束為 RandomAccessCollection:
extension MutableCollection where Self: RandomAccessCollection {
public mutating func sort<T: Comparable>(_ predicate: (Element) -> T, by areInIncreasingOrder: (T, T) -> Bool) {
sort {
areInIncreasingOrder(predicate($0), predicate($1))
}
}
public mutating func sort<T: Comparable, U: Comparable>(_ primary: ((Element) -> T, (T, T) -> Bool), _ secondary: ((Element) -> U, (U, U) -> Bool)) {
sort {
let lhs = primary.0($0)
let rhs = primary.0($1)
guard lhs == rhs else {
return primary.1(lhs, rhs)
}
return secondary.1(secondary.0($0), secondary.0($1))
}
}
public mutating func sort<T: Comparable, U: Comparable, V: Comparable>(_ primary: ((Element) -> T, (T, T) -> Bool), _ secondary: ((Element) -> U, (U, U) -> Bool), _ tertiary: ((Element) -> V, (V, V) -> Bool)) {
sort {
let lhs1 = primary.0($0)
let rhs1 = primary.0($1)
guard lhs1 == rhs1 else {
return primary.1(lhs1, rhs1)
}
let lhs2 = secondary.0($0)
let rhs2 = secondary.0($1)
guard lhs2 == rhs2 else {
return secondary.1(lhs2, rhs2)
}
return tertiary.1(tertiary.0($0), tertiary.0($1))
}
}
}
游樂場測試:
struct User: Equatable {
let name: String
let age: Int
}
var users: [User] = [
.init(name: "Liza", age: 19),
.init(name: "John", age: 19),
.init(name: "Steve", age: 51)
]
let sorted = users.sorted((\.age, >),(\.name, <)) // [{name "Steve", age 51}, {name "John", age 19}, {name "Liza", age 19}]
users.sort((\.age, >),(\.name, <)) // [{name "Steve", age 51}, {name "John", age 19}, {name "Liza", age 19}]
users == sorted // true
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.