Сортировка объектов в массиве по дате

У меня есть массив, содержащий объект с именем 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 которая рассчитывается на основе строки даты. Если вы не хотите этого делать, вы можете:

  1. Сопоставьте свой массив объектов истории с массивом объектов Date, используя 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) }

Если вы добавите отложенную 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) }