我在Swift 3中排序了一系列词典。
在Swift 2中,我会这样做,这很好用:
var dicArray = [Dictionary<String, String>()]
let dic1 = ["last": "Smith", "first": "Robert"]
dicArray.append(dic1)
let dic2 = ["last": "Adams", "first": "Bill"]
dicArray.append(dic2)
let sortedArray = dicArray.sort { ($0["last"] as? String) < ($1["last"] as? String) }
将相同的代码转换为Swift 3并不顺利。系统引导我(通过迂回路线):
let sortedArray = dicArray.sorted { ($0["last"]! as String) < ($1["last"]! as String) }
但该应用程序总是崩溃,并且在解开Optional值时发现错误为nil。
将我的头撞在桌子上太长时间后,把所有可能的组合放在一起,我采用了一种旧方法来完成工作:
let sortedArray = (dicArray as NSArray).sortedArray(using: [NSSortDescriptor(key: "last", ascending: true)]) as! [[String:AnyObject]]
这很有效,而且我一直在前进,但它不是很快,是吗?
一切都出错了?如何在这种情况下使纯Swift排序功能起作用?
答案 0 :(得分:8)
哪里出错了?
你的第一行出了问题:
var dicArray = [Dictionary<String, String>()]
即使在Swift 2中,永远不会做你想要的,因为你实际上是在数组中插入一个额外的空字典。这就是崩盘的来源;空字典没有"last"
键,因为它是空的。
你想要这个:
var dicArray = [Dictionary<String, String>]()
看到区别?在那次改变之后,一切都会到位:
var dicArray = [Dictionary<String, String>]()
let dic1 = ["last": "Smith", "first": "Robert"]
dicArray.append(dic1)
let dic2 = ["last": "Adams", "first": "Bill"]
dicArray.append(dic2)
let sortedArray = dicArray.sorted {$0["last"]! < $1["last"]!}
// [["first": "Bill", "last": "Adams"], ["first": "Robert", "last": "Smith"]]
答案 1 :(得分:1)
通常建议您创建自己的自定义类型,而不是使用带有固定密钥集的字典:
struct Person {
let lastName: String
let firstName: String
}
这样,您就不必担心是否在字典中获得了特定值的键,因为编译器会强制检查属性的名称。它可以更轻松地编写健壮,无错误的代码。
而且,巧合的是,它也使分拣更清洁。要使此自定义类型可排序,请使其符合Comparable
协议:
extension Person: Comparable {
public static func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.lastName == rhs.lastName && lhs.firstName == rhs.firstName
}
public static func < (lhs: Person, rhs: Person) -> Bool {
// if lastnames are the same, compare first names,
// otherwise we're comparing last names
if lhs.lastName == rhs.lastName {
return lhs.firstName < rhs.firstName
} else {
return lhs.lastName < rhs.lastName
}
}
}
现在,你可以对它们进行排序,保持比较逻辑很好地封装在Person
类型中:
let people = [Person(lastName: "Smith", firstName: "Robert"), Person(lastName: "Adams", firstName: "Bill")]
let sortedPeople = people.sorted()
现在,诚然,上面提到了你如何比较选项的隐含问题。因此,下面是firstName
和lastName
是选项的示例。但是,我并没有担心放置?
或!
的位置,而是使用nil
- 合并运算符,??
或switch
声明,例如:
struct Person {
let lastName: String?
let firstName: String?
}
extension Person: Comparable {
public static func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.lastName == rhs.lastName && lhs.firstName == rhs.firstName
}
public static func < (lhs: Person, rhs: Person) -> Bool {
// if lastnames are the same, compare first names,
// otherwise we're comparing last names
var lhsString: String?
var rhsString: String?
if lhs.lastName == rhs.lastName {
lhsString = lhs.firstName
rhsString = rhs.firstName
} else {
lhsString = lhs.lastName
rhsString = rhs.lastName
}
// now compare two optional strings
return (lhsString ?? "") < (rhsString ?? "")
// or you could do
//
// switch (lhsString, rhsString) {
// case (nil, nil): return false
// case (nil, _): return true
// case (_, nil): return false
// default: return lhsString! < rhsString!
// }
}
}
switch
语句更明确地处理nil
值(例如,在非可选值之前或之后排序的nil
)并将区分nil
值如果你需要的话,还有一个空字符串。 nil
合并算子更简单(恕我直言,对最终用户更直观),但如果需要,可以使用switch
方法。
答案 2 :(得分:0)
让描述符:NSSortDescriptor = NSSortDescriptor.init(key:“ YOUR KEY”,升序:true)
让sortedResults:NSArray = tempArray.sortedArray(使用[descriptor])作为NSArray