根据动态属性列表对 Swift 数组进行排序

Sorting Swift Array according to dynamic list of attributes

我有一个动态属性数组,例如:

var compareAttributes = ["name", "is_active", "age"]

项目及其数量始终可以更改。

我需要根据此列表中的所有属性(按顺序)对数组进行排序,所有属性都是 ACCEDING。

我尝试使用 NSSortDiscrptors 的 OBJ-C 方式,但由于我的数组包含 [JSON] 个对象,我无法将其转换为 NSArray :

class func sortServerObjectsByCompareAttributes( responseObjects: [JSON]) {

        var sortDiscriptors = [NSSortDescriptor]()
        for attribute in compareAttributes {
            sortDiscriptors.append(NSSortDescriptor(key: attribute, ascending: true))
        }

        let sortedByAge = (responseObjects as NSArray).sortedArrayUsingDescriptors(sortDiscriptors) // error is [JSON] is not convertible to NSArray
    }

我知道如何用 1 属性 排序:

 responseObjects.sortInPlace({[=13=][compareAttribute] < [compareAttribute]})

我需要的是这样的方法:

fun sortArray(responseObjects: [JSON], sortProperties: [string]) {
     //perform the sort
}

我怎样才能以 swift 的方式实现它?

谢谢

我不确定你想在这方面走多远。找到一个 Swifty 方法来做到这一点并不容易,因为 Swift 具有严格的类型并且没有内省。在 Objective-C 中实现您自己的按排序描述符排序方法的所有事情都很难在 Swift 中完成。 NSSortDescriptor 依赖于键值编码,这正是 JSON 对象中 缺失的 因为它是一个 Swift 结构。您在这里需要的是一个 NSObject 衍生物。如果您一直使用内置的 NSJSONSerialization,那么这就是您现在所拥有的,剩下的就很容易了。但是,当您改用 SwiftJSON 时,您就放弃了该功能。

但是,作为在特殊情况下如何通过 "key" 进行子排序的示例,让我们想象这样的事情:

protocol StringSubscriptable {
    subscript(which:String) -> String {get}
}

struct Thing : StringSubscriptable {
    var p1 : String
    var p2 : String
    var p3 : String
    subscript(which:String) -> String {
        switch which {
        case "p1": return p1
        case "p2": return p2
        case "p3": return p3
        default: return ""
        }
    }
}

你看到我在这里构造了什么了吗?这是一个纯 Swift 结构,Thing,它具有我手动设置为键值编码的属性,实际上是通过提供一个 subscript 方法来获取其每个属性的字符串值基于 属性.

的字符串名称

StringSubscriptable 协议只是一种基于协议的方式来保证 Thing 具有这种能力。

考虑到所有这些,我们可以扩展 Array 来满足您的要求:

extension Array where Element : StringSubscriptable {
    mutating func sortByList(list:[String]) {
        func sortHelper(a:StringSubscriptable, _ b:StringSubscriptable, _ ix:Int) -> Bool {
            let key = list[ix]
            if a[key] == b[key] && ix < list.count - 1 {
                return sortHelper(a, b, ix + 1)
            }
            return a[key] < b[key]
        }
        self.sortInPlace { sortHelper([=11=], , 0) }
    }
}

我们的想法是,您将 sortByList 一个键列表交给我们,然后我们根据这些键按顺序对 Thing 数组(因为它是一个 StringSubscriptable)进行排序。对于每一对,如果第一个键足以确定结果,我们将对其进行排序,但如果第一个键为这对键给出相同的结果,我们将使用第二个键代替(这就是子排序的意义所在)。

举例说明:

    let t1 = Thing(p1: "y", p2: "ho", p3: "x")
    let t2 = Thing(p1: "z", p2: "ho", p3: "x")
    let t3 = Thing(p1: "z", p2: "ho", p3: "a")
    var arr = [t1,t2,t3]
    arr.sortByList(["p3", "p2", "p1"])

结果是

[
 Thing(p1: "z", p2: "ho", p3: "a"), 
 Thing(p1: "y", p2: "ho", p3: "x"), 
 Thing(p1: "z", p2: "ho", p3: "x")
]

如果您仔细想想,这就是正确答案。首先,我们对 "p3" 进行排序,因此具有 p3"a" 的事物排在第一位。但对于另外两个,它们的 p3 值是相同的,所以我们求助于它们的 p3 值。它们也相同,所以我们求助于它们的 p1 值,并且 "y" 出现在 "z".

之前