Reputation: 597
So I have an array of Date
objects, for example:
[2020-09-07 00:00:00 +0000, 2020-09-14 00:00:00 +0000, 2020-09-15 00:00:00 +0000, 2020-09-16 00:00:00 +0000, 2020-09-23 00:00:00 +0000, 2020-10-12 00:00:00 +0000, 2020-10-13 00:00:00 +0000, 2020-10-14 00:00:00 +0000, 2020-10-15 00:00:00 +0000, 2020-10-16 00:00:00 +0000]
I have to split up this array into multiple arrays containing consecutive date ranges. The result should be like this:
[2020-09-07 00:00:00 +0000],
[2020-09-14 00:00:00 +0000, 2020-09-15 00:00:00 +0000, 2020-09-16 00:00:00 +0000],
[2020-09-23 00:00:00 +0000],
[2020-10-12 00:00:00 +0000, 2020-10-13 00:00:00 +0000, 2020-10-14 00:00:00 +0000, 2020-10-15 00:00:00 +0000, 2020-10-16 00:00:00 +0000]
What is the best way to achieve this in Swift?
Upvotes: 0
Views: 1938
Reputation: 236360
You can create some helpers to get a time insensitive date and the date after a date to compare your dates for equality as shown in this post and group the dates as shown in this post:
extension Date {
var dayAfter: Date { Calendar.current.date(byAdding: .day, value: 1, to: noon)! }
var noon: Date { Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)! }
}
extension Collection where Element == Date {
var grouped: [[Element]] {
return reduce(into: []) {
$0.last?.last?.dayAfter == $1.noon ?
$0[$0.index(before: $0.endIndex)].append($1) :
$0.append([$1])
}
}
}
extension Formatter {
static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
formatter.timeZone = TimeZone.init(secondsFromGMT: 0)!
return formatter
}()
}
let arr = ["2020-09-07 00:00:00 +0000", "2020-09-14 00:00:00 +0000", "2020-09-15 00:00:00 +0000", "2020-09-16 00:00:00 +0000", "2020-09-23 00:00:00 +0000", "2020-10-12 00:00:00 +0000", "2020-10-13 00:00:00 +0000", "2020-10-14 00:00:00 +0000", "2020-10-15 00:00:00 +0000", "2020-10-16 00:00:00 +0000"]
let dates = arr.compactMap(Formatter.iso8601.date)
let grouped = dates.grouped
print(grouped) // [[2020-09-07 00:00:00 +0000], [2020-09-14 00:00:00 +0000, 2020-09-15 00:00:00 +0000, 2020-09-16 00:00:00 +0000], [2020-09-23 00:00:00 +0000], [2020-10-12 00:00:00 +0000, 2020-10-13 00:00:00 +0000, 2020-10-14 00:00:00 +0000, 2020-10-15 00:00:00 +0000, 2020-10-16 00:00:00 +0000]]
// to convert the dates back to strings:
let dateStrings = grouped.map { $0.map(Formatter.iso8601.string) }
print(dateStrings) // [["2020-09-07 00:00:00 +0000"], ["2020-09-14 00:00:00 +0000", "2020-09-15 00:00:00 +0000", "2020-09-16 00:00:00 +0000"], ["2020-09-23 00:00:00 +0000"], ["2020-10-12 00:00:00 +0000", "2020-10-13 00:00:00 +0000", "2020-10-14 00:00:00 +0000", "2020-10-15 00:00:00 +0000", "2020-10-16 00:00:00 +0000"]]
Upvotes: 3
Reputation: 24341
Let's assume your String
array is,
let arr = ["2020-09-07 00:00:00 +0000", "2020-09-14 00:00:00 +0000", "2020-09-15 00:00:00 +0000", "2020-09-16 00:00:00 +0000", "2020-09-23 00:00:00 +0000", "2020-10-12 00:00:00 +0000", "2020-10-13 00:00:00 +0000", "2020-10-14 00:00:00 +0000", "2020-10-15 00:00:00 +0000", "2020-10-16 00:00:00 +0000"]
1. Get dateArr
of type [Date]
using are
,
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let dateArr = arr.compactMap { formatter.date(from: $0) }
2. Sort the dateArr
in ascending order,
let sortedDateArr = dateArr.sorted { $0.compare($1) == .orderedAscending }
3. You can now split up the sortedDateArr
like so,
var result = [[String]]()
var tempArr = [String]()
for (index, date) in sortedDateArr.enumerated() {
tempArr.append(formatter.string(from: date))
if index+1 < sortedDateArr.count {
if let days = Calendar.current.dateComponents([.day], from: date, to: sortedDateArr[index+1]).day, days > 1 {
result.append(tempArr)
tempArr = []
}
} else {
result.append(tempArr)
}
}
Upvotes: 2