arrays - 在 New Swift 中对二维数组进行排序,之前的排序不起作用

标签 arrays swift sorting multidimensional-array xcode7.1

您好,非常感谢您的帮助。我是 swift 的新手,已经彻底研究了其他答案,但它们都不适合我。我有以下格式的示例数据:

["10-24-2015", "124", "Yes", "No", "No", "Yes", "Yes", "NA", "NA"]

只有 3 个条目具有不同的日期和值,它们都在主数组中。它已经被写入一个文件,所以我从一个加载的文件开始我的代码。我想做的就是按日期对数组进行排序,这是每个数组中的第一个值。

大多数已经发布的答案的问题是它们使用了旧代码,我尽力尝试转换它们,但没有成功。在几天前 XCode 7.1 发布之前,我一直在使用 XCode 7.1 beta。我得到的最接近的是下面,它没有给我编译器错误,而是一个很大的退出应用程序异常错误。我还包括了其他我尝试过的评论和我得到的错误。

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 {$0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }  
    // Error: Value of type '[String]' has no member 'localizedCaseInsensitiveCompare'

    // var sortedArray = resultsArray.sort({ $0.0 > $1.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 函数,并传递一个包含两个(外部)数组元素的闭包,如果第一个元素返回 true应该排在第二个之前。您的元素属于 [String] 类型——即字符串数组——因此要按子数组元素之一排序,您只需查找并比较它们。

let sorted = resultsArray.sort { left, right in
    left[0] < right[0]
}
// or a shorter syntax:
let sorted2 = resultsArray.sort { $0[0] < $1[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 $0 {
                case "Yes": return true
                case "No": return false
                default: return nil
            }
        }
    }
}

现在您可以为每个结果拥有真实的对象,这样您就可以更好地跟踪以后的代码中的内容。让我们创建一个 Result 对象数组,并对它进行排序:

let results = resultsArray.map(Result.init).sort {
    $0.date.compare($1.date) == .OrderedAscending
}

等等,我们这样做了多少次?

您正在执行所有数据加载和排序(以及日期解析,并转换为 Result 对象,如果您遵循我上面的建议)都在 tableView(_:cellForRowAtIndexPath: ) 方法。此方法针对表中的每一行调用一次...这大概是由于您还在 tableView(_:numberOfRowsInSection:) 方法中加载了数据,是数据文件中的结果数。这意味着您一次又一次地做同样的工作,并减慢表的初始加载速度(以及任何后续的重新加载,以及行缓存溢出时的滚动)。

将数据加载、解析和排序代码移动到只执行一次的地方(或者每次更改基础数据文件并希望重新加载其更新内容时执行一次)。也许是 viewDidLoad,也许是您稍后可以再次调用的实用方法。将其结果保存在 TableView Controller 的实例属性中。然后,您可以在需要时更快地引用这些结果。

例如(用一些伪代码缩短):

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 {
            $0.date.compare($1.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
    }
}

关于arrays - 在 New Swift 中对二维数组进行排序,之前的排序不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33354144/

相关文章:

ios - 不确定如何将我的 swift 1.2 转换为 2.0 或者我是否应该

ios - 无法在导航栏中设置左栏按钮项?

ios - CocoaPods:[!] 无法找到 'Surge4Swift3' 的规范

java - 遗传算法 - 分组人 : Only find solutions containing criteria X, Y 和 Z

javascript - 如何拆分字符串对象然后连接并添加到数组

javascript - 在 Javascript 数组中对连续的重复值进行分组

javascript - 我在 Javascript 中有一个对象数组。如何循环遍历它以查找 'fname' 键的出现次数

用于扩展图像的 Python 函数(NumPy 数组)

c++ - partial_sort 和智能指针

c++ - 如何对抽象类对象进行排序