首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在日期数组中查找连续的天数

问在日期数组中查找连续的天数
EN

Code Review用户
提问于 2017-04-04 10:24:26
回答 1查看 7.2K关注 0票数 4

问题是:

如何从数量未知的日期对象数组中获得最大的连续天数,方法是只考虑4月4日、4月5日等天数。

示例输入数据:

代码语言:javascript
复制
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天

如何改进这一解决方案?

解决方案:

代码语言:javascript
复制
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)
EN

回答 1

Code Review用户

回答已采纳

发布于 2017-04-04 15:00:12

不要用86,400秒作为一天的持续时间。“大多数”天有24小时,但在夏令时,一天可以有23或25小时(当时钟调整一个小时前进或后退)。

另一个问题是,您比较了两天之间以秒为单位的差,以便确定它们是否在同一天。然后,例如“4月3日,10:00”和“4月4日,09:00”将被视为同一天。

最后一个循环中也有一个错误:如果两个日期间隔超过一天,则退出循环,而不是继续搜索更长的连续日期序列。

首先,我将计算以天为单位到某个参考日期的差值:

代码语言:javascript
复制
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!
}

现在,我们有了一个(非递减)整数数组,在您的示例中,

代码语言:javascript
复制
print(dayDiffs)
// [0, 1, 1, 1, 2, 3, 3, 3, 4, 5]

它仍然需要在该数组中找到最长的连续数字序列(忽略重复项),即从现在起不需要计算日期/日历。

这应该在一个单独的函数中完成,该函数可以如下所示:

代码语言:javascript
复制
/// 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)。

您应该添加单元测试以验证该函数是否正确工作。对于整数数组来说,这比对日期数组更容易。

在这些准备工作中,连续的天数仅为

代码语言:javascript
复制
let consecutiveDaysCount = maximalConsecutiveNumbers(in: dayDiffs)
票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/159788

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档