簡體   English   中英

動態地將帶有鍵路徑的閉包傳遞給排序 function

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM