Сортировка объектов в массиве по дате
У меня есть массив, содержащий объект с именем HistoryObject
, и он имеет такие свойства, как "дата", "имя" и т.д.
Я сортирую массив следующим образом:
let sortedArray = HistoryArray.sort({ $0.date.compare($1.date) == NSComparisonResult.OrderedDescending})
который должен сортировать дату от более старой до самой старой. Например:
- 30 июня 2016 г.
- 29 июня 2016 г.
и т.д..
Но когда мой массив содержит "2 июля 2016 года", отсортированный массив будет выглядеть следующим образом:
- 30 июня 2016 г.
- 29 июня 2016 г.
- 2 июля 2016 г.
Где "2 июля 2016 года" должно быть сверху после сортировки, теперь это на дне? Как я могу исправить эту проблему?
Ответы
Ответ 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
Например, у вас есть массив с датами и еще один массив, в котором вы сохраните преобразованные даты:
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)
Ответ 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)
Ответ 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)
Ответ 4
У вас есть массив historyArray
который содержит массив HistoryObject
. Каждый HistoryObject
содержит строку даты в форме "MM dd, yyyy"
Редактировать:
(Вы хотите отсортировать объекты истории по их значениям даты. Плохо пытаться сортировать объекты со строками даты по этим строкам даты, так как вам нужно преобразовывать строки Date
объекты даты Cocoa для каждого сравнения, поэтому вы заканчиваете преобразование дат в объекты даты снова и снова и снова. В тесте, который я сделал, это заставляет сортировку работать в 1200 раз медленнее, чем при пакетном преобразовании строк Date
объекты Date
перед сортировкой, как показано ниже.)
Для того, чтобы сделать это эффективно, вы должны сначала получить значения Date
для всех объектов. Один из способов сделать это - добавить ленивую HistoryObject
Date
в HistoryObject
которая рассчитывается на основе строки даты. Если вы не хотите этого делать, вы можете:
- Сопоставьте свой массив объектов истории с массивом объектов Date, используя DateFormatter.
- Используйте функцию
zip()
чтобы объединить массив объектов истории и массив объектов даты в массив кортежей. - Сортировать массив кортежей.
- Сопоставьте массив кортежей с массивом объектов истории.
Код для этого может выглядеть примерно так:
Версия 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) }
Если вы добавите отложенную lazy var date
в ваш HistoryObject, код сортировки будет намного проще:
Версия 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) }