问题是:
如何从数量未知的日期对象数组中获得最大的连续天数,方法是只考虑4月4日、4月5日等天数。
示例输入数据:
let calendar = Calendar.current
let x1 = Date()
let x2 = calendar.date(byAdding: .day, value: 1, to: x1)!
let x3 = calendar.date(byAdding: .day, value: 1, to: x2)!
let x4 = calendar.date(byAdding: .day, value: 1, to: x3)!
let x5 = calendar.date(byAdding: .day, value: 1, to: x4)!
let x6 = calendar.date(byAdding: .day, value: 1, to: x5)!
let x7 = calendar.date(byAdding: .hour, value: 1, to: x4)!
let x8 = calendar.date(byAdding: .hour, value: 2, to: x4)!
let x9 = calendar.date(byAdding: .hour, value: 3, to: x2)!
let x10 = calendar.date(byAdding: .hour, value: 4, to: x2)!
var dates = [Date]()
dates.append(x1)
dates.append(x5)
dates.append(x2)
dates.append(x3)
dates.append(x4)
dates.append(x6)
dates.append(x7)
dates.append(x8)
dates.append(x9)
dates.append(x10)样本数据的预期结果:连续6天
如何改进这一解决方案?
解决方案:
dates.sort(by: < )
// extract only unique days
var dateIndex = 0
var nextDateIndex = 1
repeat {
let date = dates[dateIndex]
let nextDate = dates[nextDateIndex]
if calendar.isDate(nextDate, inSameDayAs: date) {
dates.remove(at: nextDateIndex)
} else {
dateIndex += 1
nextDateIndex += 1
}
} while (dateIndex < dates.count - 1)
print(dates)
let aDayInSeconds: TimeInterval = 86_400
let twoDaysInSeconds: TimeInterval = 172_800
var consecutiveDaysCount = 1
dateIndex = 0
nextDateIndex = 1
// count consecutive days
repeat {
guard (i + 1 < dates.count) else { break }
let date = dates[dateIndex]
let nextDate = dates[nextDateIndex]
if nextDate.timeIntervalSince(date) >= aDayInSeconds && nextDate.timeIntervalSince(date) < twoDaysInSeconds {
dateIndex += 1
nextDateIndex += 1
consecutiveDaysCount += 1
} else {
break
}
} while (i < newDates.count - 1)
print(consecutiveDaysCount)发布于 2017-04-04 15:00:12
不要用86,400秒作为一天的持续时间。“大多数”天有24小时,但在夏令时,一天可以有23或25小时(当时钟调整一个小时前进或后退)。
另一个问题是,您比较了两天之间以秒为单位的差,以便确定它们是否在同一天。然后,例如“4月3日,10:00”和“4月4日,09:00”将被视为同一天。
最后一个循环中也有一个错误:如果两个日期间隔超过一天,则退出循环,而不是继续搜索更长的连续日期序列。
首先,我将计算以天为单位到某个参考日期的差值:
dates.sort() // Short form for: dates.sort(by: < )
let referenceDate = calendar.startOfDay(for: dates.first!)
let dayDiffs = dates.map { (date) -> Int in
calendar.dateComponents([.day], from: referenceDate, to: date).day!
}现在,我们有了一个(非递减)整数数组,在您的示例中,
print(dayDiffs)
// [0, 1, 1, 1, 2, 3, 3, 3, 4, 5]它仍然需要在该数组中找到最长的连续数字序列(忽略重复项),即从现在起不需要计算日期/日历。
这应该在一个单独的函数中完成,该函数可以如下所示:
/// Find maximal length of a subsequence of consecutive numbers in the array.
/// It is assumed that the array is sorted in non-decreasing order.
/// Consecutive equal elements are ignored.
func maximalConsecutiveNumbers(in array: [Int]) -> Int {
var longest = 0 // length of longest subsequence of consecutive numbers
var current = 1 // length of current subsequence of consecutive numbers
for (prev, next) in zip(array, array.dropFirst()) {
if next > prev + 1 {
// Numbers are not consecutive, start a new subsequence.
current = 1
} else if next == prev + 1 {
// Numbers are consecutive, increase current length
current += 1
}
if current > longest {
longest = current
}
}
return longest
}这种方法实际上类似于您上一个循环中的方法,只是
zip() + dropFirst()用于对所有相邻数组元素进行迭代,这可以节省簿记的外观(dateIndex,nextDateIndex)。您应该添加单元测试以验证该函数是否正确工作。对于整数数组来说,这比对日期数组更容易。
在这些准备工作中,连续的天数仅为
let consecutiveDaysCount = maximalConsecutiveNumbers(in: dayDiffs)https://codereview.stackexchange.com/questions/159788
复制相似问题