【问题标题】:Sort Objects in Array by date按日期对数组中的对象进行排序
【发布时间】:2016-11-05 05:37:17
【问题描述】:

我有一个数组,其中包含一个名为 HistoryObject 的对象,它具有诸如“日期”、“名称”等属性。

我正在像这样对数组进行排序:

 let sortedArray = HistoryArray.sort({ $0.date.compare($1.date) == NSComparisonResult.OrderedDescending})

应该按从新到旧对日期进行排序。例如:

  • 2016 年 6 月 30 日
  • 2016 年 6 月 29 日

等等。

但是当我的数组包含“2016 年 7 月 2 日”时,排序后的数组变为:

  • 2016 年 6 月 30 日
  • 2016 年 6 月 29 日
  • 2016 年 7 月 2 日

排序后“2016 年 7 月 2 日”应该在顶部,现在在底部?我该如何解决这个问题?

【问题讨论】:

  • 你又用过排序功能了吗?这不能自动设置。每次添加新对象时对其进行排序的唯一方法,您可以创建数组扩展,例如每次使用 AddObject 时,都必须调用此排序函数。
  • 我的意思是在我从 api 获得完整的数组之后,我用它的对象对整个数组进行排序,这意味着我在排序后不添加对象。但它没有正确排序。 @AltimirAntonov
  • 先将字符串转换为 NSDate。我会在几分钟内写出答案。

标签: arrays swift sorting


【解决方案1】:

使用 Swift 4 和 Swift 3

let testArray = ["25 Jun, 2016", "30 Jun, 2016", "28 Jun, 2016", "2 Jul, 2016"]
var convertedArray: [Date] = []

var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MM, yyyy"// yyyy-MM-dd"

for dat in testArray {
    let date = dateFormatter.date(from: dat)
    if let date = date {
        convertedArray.append(date)
    }
}

var ready = convertedArray.sorted(by: { $0.compare($1) == .orderedDescending })

print(ready)

使用 Swift 2

例如,您有一个包含日期的数组和另一个 1 个数组,您将在其中保存转换后的日期:

var testArray = ["25 Jun, 2016", "30 Jun, 2016", "28 Jun, 2016", "2 Jul, 2016"]
var convertedArray: [NSDate] = []

之后我们转换日期:

var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd MM, yyyy"// yyyy-MM-dd"

for dat in testArray {
    var date = dateFormatter.dateFromString(dat)
    convertedArray.append(date!)
}

结果:

var ready = convertedArray.sort({ $0.compare($1) == .OrderedDescending })

print(ready)

【讨论】:

  • 您没有回答 OP 的问题。 OP 想要对包含日期字符串的对象数组进行排序。您的代码仅对日期进行排序。
【解决方案2】:

对于 Swift 3

var testArray = ["25 Jun, 2016", "30 Jun, 2016", "28 Jun, 2016", "2 Jul, 2016"]
var convertedArray: [Date] = []

var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"

for dat in testArray {
    var date = dateFormatter.date(from: dat)
    convertedArray.append(date!)
}

//Approach : 1
convertedArray.sort(){$0 < $1}    

//Approach : 2
convertedArray.sorted(by: {$0.timeIntervalSince1970 < $1.timeIntervalSince1970})

print(convertedArray)

【讨论】:

  • 您没有回答 OP 的问题。 OP 想要对包含日期字符串的对象数组进行排序。您的代码仅对日期进行排序。
【解决方案3】:

避免 convertArray 的额外变量

使用 Swift 4 和 Swift 3

let testArray = ["25 Jun, 2016", "30 Jun, 2016", "28 Jun, 2016", "2 Jul, 2016"]

var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MM, yyyy"// yyyy-MM-dd"

var ready = convertedArray.sorted(by: { dateFormatter.date(from:$0).compare(dateFormatter.date(from:$1)) == .orderedDescending })

print(ready)

【讨论】:

  • 请注意,将字符串转换为日期非常耗时,并且在 sorted() call 的闭包中执行此操作会使排序非常变慢。我做了一个测试,发现对包含日期字符串的对象进行排序并在sorted() 闭包中使用DateFormatter,就像您建议的那样,排序时间比将所有日期字符串转换为日期,然后对它们进行排序。因此,这是一个非常糟糕的主意。
【解决方案4】:

斯威夫特 5

  1. 假设我们有一个对象数组,其中日期为字符串:
struct Test {
    let dateStr: String
}
let testObjects = ["25 Jun, 2016", "30 Jun, 2016", "28 Jun, 2016", "12 Jul, 2016"]
    .map(Test.init(dateStr:))
  1. 创建DateFormatter:
var dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
dateFormatter.dateFormat = "dd MMM, yyyy"
  1. map 每个项目到一个元组(测试,日期),然后sort 整个数组按日期,然后map 再次到测试对象:
let convertedObjects = testObjects
    .map { return ($0, dateFormatter.date(from: $0.dateStr)!) }
    .sorted { $0.1 > $1.1 }
    .map(\.0)

以类似的方式,我们可以将日期数组排序为字符串:

  1. 假设我们有一个数组:
let testArray = ["25 Jun, 2016", "30 Jun, 2016", "28 Jun, 2016", "12 Jul, 2016"]
  1. 创建DateFormatter:
var dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
dateFormatter.dateFormat = "dd MMM, yyyy"
  1. map 每个项目到日期然后sort 整个数组:
let convertedArray = testArray
    .compactMap(dateFormatter.date(from:))
    .sorted(by: >)

【讨论】:

  • 正确的 dateFormat 是 MMM(不是 MMMMMM 显示在接受的答案中)。
  • @LeoDabus 是的,谢谢 - 我想我只是假设一个接受超过 100 次投票的答案是正确的。我应该检查一下。
【解决方案5】:

您有一个数组historyArray,其中包含一个HistoryObject 数组。每个HistoryObject 都包含一个日期字符串,格式为“MM dd, yyyy”

编辑:

(您想按日期值对历史对象进行排序。尝试按日期字符串对具有日期字符串的对象进行排序是个坏主意,因为您必须将日期字符串转换为Cocoa Date 对象用于每次比较,因此您最终会一遍又一遍地将日期转换为日期对象。在我所做的基准测试中,这会导致排序运行速度比将日期字符串批量转换为 @ 慢 1200 倍987654325@ 排序前的对象,如下所述。)

为了有效地执行此操作,您需要首先获取所有对象的Date 值。一种方法是向您的HistoryObject 添加一个惰性Date 变量,该变量是根据日期字符串计算的。如果您不想这样做,您可以:

  1. 使用以下方法将历史对象数组映射到日期对象数组 一个 DateFormatter。
  2. 使用zip()函数组合历史对象数组和 将日期对象数组转换为元组数组。
  3. 对元组数组进行排序。
  4. 将元组数组映射回历史对象数组。

执行此操作的代码可能如下所示:

版本 1

var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM dd, yyyy"

//I don't know what your HistoryObject looks like, so I'll fake it.
struct HistoryObject: CustomStringConvertible {
    let dateString: String
    let value: Int
    
    var description: String {
        return "date: \(dateString), value: \(value)"
    }
}

//Create an array of date strings.
let testArray = ["Jun 25, 2016", "Jun 30, 2016", "Jun 28, 2016", "Jul 2, 2016"]

//Use the array of date strings to create an array of type [HistoryObject]
let historyArray: [HistoryObject] = testArray.map {
    let value = Int(arc4random_uniform(1000))
    return HistoryObject(dateString: $0, value: value)
}

print("\n-----> Before sorting <-----")
historyArray.forEach { print($0) }

//Create an array of the `Dates` for each HistoryObject
let historyDates: [Date] = historyArray.map { dateFormatter.date(from: $0.dateString)!
}

//Combine the array of `Dates` and the array of `HistoryObjects` into an array of tuples
let historyTuples = zip(historyArray, historyDates)

//Sort the array of tuples and then map back to an array of type [HistoryObject]
let sortedHistoryObjects = historyTuples.sorted { $0.1 > $1.1}
    .map {$0.0}

print("\n-----> After sorting <-----")
sortedHistoryObjects.forEach { print($0) }

如果您在 HistoryObject 中添加 lazy var date,则排序代码会简单很多:

版本 2:

//I don't know what your HistoryObject looks like, so I'll fake it.
class HistoryObject: CustomStringConvertible {
    let dateString: String
    lazy var date: Date = { dateFormatter.date(from: self.dateString)! }()
    let value: Int
    
    var description: String {
        return "date: \(dateString), value: \(value)"
    }
    
    init(dateString: String, value: Int) {
        self.dateString = dateString
        self.value = value
    }
}

//Create an array of date strings.
let testArray = ["Jun 25, 2016", "Jun 30, 2016", "Jun 28, 2016", "Jul 2, 2016"]

//Use the array of date strings to create an array of type [HistoryObject]
let historyArray: [HistoryObject] = testArray.map {
    let value = Int(arc4random_uniform(1000))
    return HistoryObject(dateString: $0, value: value)
}

print("\n-----> Before sorting <-----")
historyArray.forEach { print($0) }

let sortedHistoryArray = historyArray.sorted { $0.date > $1.date }
print("\n-----> After sorting <-----")
sortedHistoryArray.forEach { print($0) }

【讨论】:

    【解决方案6】:

    您可能想使用“.sort”而不是“.sorted”:

    convertedArray.sort { (($0)?.compare($1))! == .orderedDescending }
    

    【讨论】:

    • 值得注意的是.sort().sorted()之间的区别。
    【解决方案7】:

    请试试这个,它对我有用

    let sortArr = prescriptionList?.medicationList?.sorted(by:{
                ($0.medicationDate?.stringDateToInt(requireFormatter: "yyyy-MM-dd HH:mm:ss", needFormatter: "yyyy-MM-dd HH:mm:ss", dateStr: $0.medicationDate ?? ""))! > $1.medicationDate!.stringDateToInt(requireFormatter: "yyyy-MM-dd HH:mm:ss", needFormatter: "yyyy-MM-dd HH:mm:ss", dateStr: $1.medicationDate ?? "")
            } )
    
    extension String {
        
        func stringDateToInt(requireFormatter: String, needFormatter: String, dateStr: String) -> Int {
            var dateInt: Int = 0
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "\(requireFormatter)"
            if let date = dateFormatter.date(from: dateStr) {
                dateFormatter.dateFormat = "\(needFormatter)"
                dateInt = date.millisecondsSince1970
            }
            return dateInt
        }
    }
    

    【讨论】:

    • 我没有尝试运行这段代码,但它让我找到了答案。我正在运行 Swift 5。我发现日期按月和日正确排序,但不是年份。我的日期格式是“MM dd, yyyy HH:mm a”。改成“yyyy MM dd, HH:mm a”后,发现先排序的是年份,然后是月份,然后是日期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 2015-02-25
    • 2013-10-26
    • 1970-01-01
    相关资源
    最近更新 更多