在新 Swift 中对二维数组进行排序,之前的排序不起作用
Sort 2D Array in New Swift, previous sort not working
您好,非常感谢您的帮助。我是 swift 的新手,并且已经彻底研究了其他答案,但它们都不适合我。我有以下格式的示例数据:
["10-24-2015", "124", "Yes", "No", "No", "Yes", "Yes", "NA", "NA"]
只有 3 个条目具有不同的日期和值,它们都在主数组中。它已经被写入一个文件,所以我从一个加载的文件开始我的代码。我想做的就是按日期对数组进行排序,这是每个数组中的第一个值。
已经发布的大部分答案的问题是它们使用了较旧的代码,我尽力尝试转换它们,但没有成功。我一直在使用 XCode 7.1 beta,直到几天前 XCode 7.1 发布。我得到的最接近的是下面,它没有给我编译器错误,而是一个很大的退出应用程序异常错误。我还包括了其他我尝试过的评论和我得到的错误。
var resultsArray = [[String]]()
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "resultsViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! resultsTableViewCell
let resultsdocumentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let resultsfileURL = resultsdocumentsURL.URLByAppendingPathComponent("ResultsPlist.plist")
resultsArray = NSKeyedUnarchiver.unarchiveObjectWithFile(resultsfileURL.path!) as! Array
let Sort: NSSortDescriptor = NSSortDescriptor(key: "date", ascending: false)
let sortedArray: NSArray = (resultsArray as NSArray).sortedArrayUsingDescriptors([Sort])
// var sortedArray = resultsArray.sort {[=11=].localizedCaseInsensitiveCompare() == NSComparisonResult.OrderedAscending }
// Error: Value of type '[String]' has no member 'localizedCaseInsensitiveCompare'
// var sortedArray = resultsArray.sort({ [=11=].0 > .0 })
// Error: Value of type '[String]' has no member '0'
return cell
}
忘了说,当我使用一个示例单数组时,所有代码都没有问题。但是让它多维然后我得到我的异常错误。
这里有几个问题需要解决:
对多维数组进行排序
为了测试,我在您的 resultsArray
格式中填充了一些伪造的行:
let resultsArray = [
["10-24-2015", "124", "Yes", "No", "No", "Yes", "Yes", "NA", "NA"],
["09-23-2015", "125", "Yes", "No", "No", "No", "Yes", "NA", "NA"],
["10-21-2015", "121", "Yes", "No", "Yes", "Yes", "Yes", "NA", "NA"],
["08-24-2015", "141", "Yes", "Yes", "No", "Yes", "Yes", "NA", "NA"],
["10-24-2014", "199", "Yes", "No", "No", "Yes", "No", "NA", "NA"],
]
现在,在 Swift 中对其进行排序非常简单:调用 sort
函数,并传递一个包含两个(外部)数组元素和 returns true
如果第一个应该排在第二个之前。您的元素属于 [String]
类型——即字符串数组——因此要按子数组元素之一排序,您只需查找并比较它们。
let sorted = resultsArray.sort { left, right in
left[0] < right[0]
}
// or a shorter syntax:
let sorted2 = resultsArray.sort { [=11=][0] < [0] }
但这可能不是你想要的。
按日期排序
上面按字典顺序对字符串进行排序。这意味着您会得到这样的结果:
["08-24-2015", "141", "Yes", "Yes", "No", "Yes", "Yes", "NA", "NA"]
["09-23-2015", "125", "Yes", "No", "No", "No", "Yes", "NA", "NA"]
["10-21-2015", "121", "Yes", "No", "Yes", "Yes", "Yes", "NA", "NA"]
["10-24-2014", "199", "Yes", "No", "No", "Yes", "No", "NA", "NA"]
["10-24-2015", "124", "Yes", "No", "No", "Yes", "Yes", "NA", "NA"]
你的日期格式是月-日-年,所以当你将它们作为字符串进行比较时,你不会得到时间顺序(“08-24-2015”出现在“10-24-2014”之前,因为第一个一个以“08”开头)。
执行此操作的更好方法是解析日期,以便您可以将它们作为日期进行比较。这是一个镜头:
// parse actual dates
let formatter = NSDateFormatter()
formatter.dateFormat = "MM-dd-yyyy"
let sorted3 = resultsArray.sort { left, right in
let leftDate = formatter.dateFromString(left[0])!
let rightDate = formatter.dateFromString(right[0])!
// NSDate doesn't have a < operator, so use the Foundation compare method
return leftDate.compare(rightDate) == .OrderedAscending
}
这按您期望的方式排序。不过,您可能会变得更好。
使用模型对象
您可能想要对这些进行更多操作,因此将行视为每个字段都具有一定意义的对象可能会有所帮助。例如:
struct Result {
let date: NSDate
let number: Int
let responses: [Bool?]
init(array: [String]) {
date = formatter.dateFromString(array[0])!
number = Int(array[1])!
responses = array[2..<array.count].map {
switch [=14=] {
case "Yes": return true
case "No": return false
default: return nil
}
}
}
}
现在您可以为每个结果拥有真实的对象,这样您就可以更好地跟踪以后的代码中的内容。让我们创建一个包含 Result
个对象的数组,并对它进行排序:
let results = resultsArray.map(Result.init).sort {
[=15=].date.compare(.date) == .OrderedAscending
}
等等,我们这样做了多少次?
您正在 tableView(_:cellForRowAtIndexPath:)
方法中完成所有数据加载和排序(以及日期解析和转换为 Result
对象,如果您遵循我上面的建议)。对于 table 中的每一行,此方法被调用一次 ... 这可能是由于您还在 tableView(_:numberOfRowsInSection:)
方法中加载数据,是数字数据文件中的结果。这意味着你一次又一次地做同样的工作,并减慢你的 table 的初始加载(以及任何后续的重新加载,并在行缓存溢出时滚动)。
将数据加载、解析和排序代码移动到只执行一次的地方(或者每次更改基础数据文件并希望重新加载其更新内容时执行一次)。也许 viewDidLoad
,也许是一个你可以稍后再调用的实用方法。将其结果保存在 table 视图控制器的实例 属性 中。然后,您可以在需要时更快地参考这些结果。
例如(用一些伪代码缩短):
class MyTableViewController: UITableViewController {
let cellIdentifier = "resultsViewCell"
var results: [Result]!
override func viewDidLoad() {
let resultsdocumentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let resultsfileURL = resultsdocumentsURL.URLByAppendingPathComponent("ResultsPlist.plist")
guard let resultsArray = NSKeyedUnarchiver.unarchiveObjectWithFile(resultsfileURL.path!) as? [[String]]
else { fatalError("unexpected results from plist") }
results = resultsArray.map(Result.init).sort {
[=16=].date.compare(.date) == .OrderedAscending
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return results.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ResultsTableViewCell
let result = results[indexPath.row]
cell.textLabel?.text = result.description // or however you display a result
}
}
您好,非常感谢您的帮助。我是 swift 的新手,并且已经彻底研究了其他答案,但它们都不适合我。我有以下格式的示例数据:
["10-24-2015", "124", "Yes", "No", "No", "Yes", "Yes", "NA", "NA"]
只有 3 个条目具有不同的日期和值,它们都在主数组中。它已经被写入一个文件,所以我从一个加载的文件开始我的代码。我想做的就是按日期对数组进行排序,这是每个数组中的第一个值。
已经发布的大部分答案的问题是它们使用了较旧的代码,我尽力尝试转换它们,但没有成功。我一直在使用 XCode 7.1 beta,直到几天前 XCode 7.1 发布。我得到的最接近的是下面,它没有给我编译器错误,而是一个很大的退出应用程序异常错误。我还包括了其他我尝试过的评论和我得到的错误。
var resultsArray = [[String]]()
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "resultsViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! resultsTableViewCell
let resultsdocumentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let resultsfileURL = resultsdocumentsURL.URLByAppendingPathComponent("ResultsPlist.plist")
resultsArray = NSKeyedUnarchiver.unarchiveObjectWithFile(resultsfileURL.path!) as! Array
let Sort: NSSortDescriptor = NSSortDescriptor(key: "date", ascending: false)
let sortedArray: NSArray = (resultsArray as NSArray).sortedArrayUsingDescriptors([Sort])
// var sortedArray = resultsArray.sort {[=11=].localizedCaseInsensitiveCompare() == NSComparisonResult.OrderedAscending }
// Error: Value of type '[String]' has no member 'localizedCaseInsensitiveCompare'
// var sortedArray = resultsArray.sort({ [=11=].0 > .0 })
// Error: Value of type '[String]' has no member '0'
return cell
}
忘了说,当我使用一个示例单数组时,所有代码都没有问题。但是让它多维然后我得到我的异常错误。
这里有几个问题需要解决:
对多维数组进行排序
为了测试,我在您的 resultsArray
格式中填充了一些伪造的行:
let resultsArray = [
["10-24-2015", "124", "Yes", "No", "No", "Yes", "Yes", "NA", "NA"],
["09-23-2015", "125", "Yes", "No", "No", "No", "Yes", "NA", "NA"],
["10-21-2015", "121", "Yes", "No", "Yes", "Yes", "Yes", "NA", "NA"],
["08-24-2015", "141", "Yes", "Yes", "No", "Yes", "Yes", "NA", "NA"],
["10-24-2014", "199", "Yes", "No", "No", "Yes", "No", "NA", "NA"],
]
现在,在 Swift 中对其进行排序非常简单:调用 sort
函数,并传递一个包含两个(外部)数组元素和 returns true
如果第一个应该排在第二个之前。您的元素属于 [String]
类型——即字符串数组——因此要按子数组元素之一排序,您只需查找并比较它们。
let sorted = resultsArray.sort { left, right in
left[0] < right[0]
}
// or a shorter syntax:
let sorted2 = resultsArray.sort { [=11=][0] < [0] }
但这可能不是你想要的。
按日期排序
上面按字典顺序对字符串进行排序。这意味着您会得到这样的结果:
["08-24-2015", "141", "Yes", "Yes", "No", "Yes", "Yes", "NA", "NA"]
["09-23-2015", "125", "Yes", "No", "No", "No", "Yes", "NA", "NA"]
["10-21-2015", "121", "Yes", "No", "Yes", "Yes", "Yes", "NA", "NA"]
["10-24-2014", "199", "Yes", "No", "No", "Yes", "No", "NA", "NA"]
["10-24-2015", "124", "Yes", "No", "No", "Yes", "Yes", "NA", "NA"]
你的日期格式是月-日-年,所以当你将它们作为字符串进行比较时,你不会得到时间顺序(“08-24-2015”出现在“10-24-2014”之前,因为第一个一个以“08”开头)。
执行此操作的更好方法是解析日期,以便您可以将它们作为日期进行比较。这是一个镜头:
// parse actual dates
let formatter = NSDateFormatter()
formatter.dateFormat = "MM-dd-yyyy"
let sorted3 = resultsArray.sort { left, right in
let leftDate = formatter.dateFromString(left[0])!
let rightDate = formatter.dateFromString(right[0])!
// NSDate doesn't have a < operator, so use the Foundation compare method
return leftDate.compare(rightDate) == .OrderedAscending
}
这按您期望的方式排序。不过,您可能会变得更好。
使用模型对象
您可能想要对这些进行更多操作,因此将行视为每个字段都具有一定意义的对象可能会有所帮助。例如:
struct Result {
let date: NSDate
let number: Int
let responses: [Bool?]
init(array: [String]) {
date = formatter.dateFromString(array[0])!
number = Int(array[1])!
responses = array[2..<array.count].map {
switch [=14=] {
case "Yes": return true
case "No": return false
default: return nil
}
}
}
}
现在您可以为每个结果拥有真实的对象,这样您就可以更好地跟踪以后的代码中的内容。让我们创建一个包含 Result
个对象的数组,并对它进行排序:
let results = resultsArray.map(Result.init).sort {
[=15=].date.compare(.date) == .OrderedAscending
}
等等,我们这样做了多少次?
您正在 tableView(_:cellForRowAtIndexPath:)
方法中完成所有数据加载和排序(以及日期解析和转换为 Result
对象,如果您遵循我上面的建议)。对于 table 中的每一行,此方法被调用一次 ... 这可能是由于您还在 tableView(_:numberOfRowsInSection:)
方法中加载数据,是数字数据文件中的结果。这意味着你一次又一次地做同样的工作,并减慢你的 table 的初始加载(以及任何后续的重新加载,并在行缓存溢出时滚动)。
将数据加载、解析和排序代码移动到只执行一次的地方(或者每次更改基础数据文件并希望重新加载其更新内容时执行一次)。也许 viewDidLoad
,也许是一个你可以稍后再调用的实用方法。将其结果保存在 table 视图控制器的实例 属性 中。然后,您可以在需要时更快地参考这些结果。
例如(用一些伪代码缩短):
class MyTableViewController: UITableViewController {
let cellIdentifier = "resultsViewCell"
var results: [Result]!
override func viewDidLoad() {
let resultsdocumentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let resultsfileURL = resultsdocumentsURL.URLByAppendingPathComponent("ResultsPlist.plist")
guard let resultsArray = NSKeyedUnarchiver.unarchiveObjectWithFile(resultsfileURL.path!) as? [[String]]
else { fatalError("unexpected results from plist") }
results = resultsArray.map(Result.init).sort {
[=16=].date.compare(.date) == .OrderedAscending
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return results.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ResultsTableViewCell
let result = results[indexPath.row]
cell.textLabel?.text = result.description // or however you display a result
}
}