在Swift中使用多个条件对字典数组进行排序

时间:2015-10-16 00:41:41

标签: ios arrays swift

我有一个字典数组,我的字典是[String:AnyObject]。以下是一些数据:

[{
    name = Joe;
    score = 50;
    favorite = Phone;
    startDate = "2015-10-15";
    startingTime = "2015-10-15 19:00:00 +0000";
    finished = "<null>";
}, {
    name = Mark;
    score = 60;
    favorite = Phone;
    startDate = "2015-10-16”;
    startingTime = "2015-10-16 19:00:00 +0000";
    finished = "<null>";
}, {
    name = Joe;
    score = 30;
    favorite = Phone;
    startDate = "2015-10-15";
    startingTime = "2015-10-15 19:00:00 +0000";
    finished = "<null>";
}]

我想要的是能够先按名称排序,然后按开始时间排序,然后如果两者都匹配则按分数排序(我将分数存储为字符串)。

我知道这是非常错误但是我输入了:

test.sort({ $0.name! < $1.name! })

这给了我一个错误“无法使用'((_,_) - &gt; _)'类型的参数列表调用'sort'。”

任何人都可以对如何做到这一点有所了解吗?

**已更新为具有答案的视图控制器中的代码

    import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var allArray = [AnyObject]()
        var array = [String:AnyObject]()

        array["name"] = "Joe"
        array["score"] = 50 as Int
        array["favorite"] = "Phone"
        array["startDate"] = "2015-10-15"
        let date = NSDate()
        array["date"] = date
        array["finished"] = nil
        allArray.append(array)

        array["name"] = "Mark"
        array["score"] = 60 as Int
        array["favorite"] = "Phone"
        array["startDate"] = "2015-10-16"
        array["date"] = date
        array["finished"] = nil
        allArray.append(array)

        array["name"] = "Joe"
        array["score"] = 30 as Int
        array["favorite"] = "Phone"
        array["startDate"] = "2015-10-15"
        array["date"] = date
        array["finished"] = nil
        allArray.append(array)
        println(allArray)

        allArray.sort {
            if let name0 = $0["name"] as? String, name1 = $1["name"] as? String
                where name0 != name1 {
                    return name0 < name1
            }

            // You said 'startingTime' in your question your code showed 'date'
            if let date0 = $0["date"] as? NSDate, date1 = $1["date"] as? NSDate
                where date0.timeIntervalSince1970 != date1.timeIntervalSince1970 {
                    return date0.timeIntervalSince1970 < date1.timeIntervalSince1970
            }

            // You have 'score' as String. I think you would want a numeric type instead
            return ($0["score"] as! Int) < ($1["score"] as! Int)
        }

        println(allArray)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

谢谢!

4 个答案:

答案 0 :(得分:1)

如果编译器变得奇怪,请尝试使用闭包参数更明确。

这种排序方法似乎对我有用。

arr = arr.sort { a, b in
    if a["name"] == b["name"] {
        if a["startingTime"] == b["startingTime"] {
            return a["score"] > b["score"]
        }
        return a["startingTime"] > b["startingTime"]
    } else {
        return a["name"] > b["name"]
    }
}

答案 1 :(得分:0)

看起来这很有效,警卫就是这样,我不必在比较中处理打开(因为这样我爱护,使代码更清洁IMO)

let test : [[String:AnyObject]] = [["name":"joe", "time":1, "score":5], ["name":"joe", "time":1, "score":3], ["name":"joe", "time":1, "score":7]]

let sorted = test.sort{
    guard let name = $0["name"] as? String,
    let time = $0["time"] as? Int,
    let score = $0["score"] as? Int,
    let name1 = $1["name"] as? String,
    let time1 = $1["time"] as? Int,
    let score1 = $1["score"] as? Int else{
            //unwrapping failed, sort is going to be bad
            return false
    }

    if name == name1 {
        if time == time1 {
            return score < score1
        }else {
            return time < time1
        }
    }else {
        return name < name1
    }

}

print(sorted)

答案 2 :(得分:0)

以下是一些使给定代码更好的代码片段。首先将这些添加到文件的开头,以使日期可比。

    public func ==(lhs: NSDate, rhs: NSDate) -> Bool {
        return lhs === rhs || lhs.compare(rhs) == .OrderedSame
    }

    public func <(lhs: NSDate, rhs: NSDate) -> Bool {
        return lhs.compare(rhs) == .OrderedAscending
    }

    extension NSDate: Comparable { }

然后在你的方法中使用下面的语法(这是swift 2):

    var allArray = [AnyObject]()
    var array = [String:AnyObject]()

    array["name"] = "Joe"
    array["score"] = "50"
    array["favorite"] = "Phone"
    array["startDate"] = "2015-10-15"
    let date = NSDate()
    array["startingTime"] = date
    array["finished"] = nil
    allArray.append(array)

    array["name"] = "Mark"
    array["score"] = "60"
    array["favorite"] = "Phone"
    array["startDate"] = "2015-10-16"
    array["startingTime"] = date
    array["finished"] = nil
    allArray.append(array)

    array["name"] = "Joe"
    array["score"] = "30"
    array["favorite"] = "Phone"
    array["startDate"] = "2015-10-15"
    array["startingTime"] = date
    array["finished"] = nil
    allArray.append(array)
    print(allArray)

    allArray.sortInPlace { i,j in (i["name"] as! String) < (j["name"] as! String) || (i["startingTime"] as! NSDate) < (j["startingTime"] as! NSDate) }

我更喜欢你使用这样的语法。这是一种更快捷的方式来声明一系列字典。

    let xyz = [
        [
            "name" : "Joe",
            "score" : 50,
            "favorite" : "Phone",
            "startDate" : "2015-10-15",
            "startingTime" : "2015-10-15 19:00:00 +0000",
            "finished" : "<null>"
        ], [
            "name" : "Mark",
            "score" : 60,
            "favorite" : "Phone",
            "startDate" : "2015-10-16",
            "startingTime" : "2015-10-16 19:00:00 +0000",
            "finished" : "<null>"
        ], [
            "name" : "Joe",
            "score" : 30,
            "favorite" : "Phone",
            "startDate" : "2015-10-15",
            "startingTime" : "2015-10-15 19:00:00 +0000",
            "finished" : "<null>"
        ]
    ]
    var test = xyz.sort { ($0["name"] as! String) < ($1["name"] as! String) }

答案 3 :(得分:0)

只是将我的解决方案添加到已经拥挤的答案中,因为现有的答案都不令我满意。

// allArray is as initiated in your viewDidLoad method

let sortedArray = allArray.sort {
    if let name0 = $0["name"] as? String, name1 = $1["name"] as? String
        where name0 != name1 {
            return name0 < name1
    }

    // You said 'startingTime' in your question but your code showed 'date'
    if let date0 = $0["date"] as? NSDate, date1 = $1["date"] as? NSDate
        where date0.timeIntervalSince1970 != date1.timeIntervalSince1970 {
            return date0.timeIntervalSince1970 < date1.timeIntervalSince1970
    }

    // You have 'score' as String. I think you would want a numeric type instead
    return ($0["score"] as! Int) < ($1["score"] as! Int)
}

代码充满了强制转换,因为您使用AnyObject作为值类型。