为什么Kotlin';s generateSequence在下面的示例中返回的项目过多?

为什么Kotlin';s generateSequence在下面的示例中返回的项目过多?,kotlin,sequence,Kotlin,Sequence,我正在基于cron表达式计算瞬间在时间上的投影,并将它们作为序列返回。下面是课程: //(包省略) 导入org.springframework.scheduling.support.CronExpression 导入java.time.Instant 导入java.time.LocalDate 导入java.time.LocalDateTime 导入java.time.zoneDateTime 导入java.time.temporal.ChronoUnit 类重复(val-cronExpress

我正在基于cron表达式计算瞬间在时间上的投影,并将它们作为
序列返回。下面是课程:

//(包省略)
导入org.springframework.scheduling.support.CronExpression
导入java.time.Instant
导入java.time.LocalDate
导入java.time.LocalDateTime
导入java.time.zoneDateTime
导入java.time.temporal.ChronoUnit
类重复(val-cronExpression:String){
private val cron=CronExpression.parse(CronExpression)
有趣的瞬间(
fromInclusive:LocalDate=LocalDate.now(),
toExclusive:LocalDate=fromInclusive.plusMonths(1)
):Sequence=实例(从inclusive.atStartOfDay()到exclusive.atStartOfDay())
有趣的瞬间(
fromInclusive:LocalDateTime=LocalDateTime.now(),
toExclusive:LocalDateTime=fromInclusive.plusMonths(1)
):顺序{
返回generateSequence(cron.next(fromInclusive.minusNanos(1))){
如果(它在(排除)之前){
cron.next(it)
}否则{
无效的
}
}
}
}
以下测试失败,因为第一个断言为false:返回的列表末尾有一个额外的意外元素

//(包省略)
导入java.time.LocalDate
导入java.time.Month
导入kotlin.test.test
导入kotlin.test.assertEquals
类重现性检验{
@试验
有趣的测试者(){
val r=重复(“每日”)
val from=LocalDate.of(2021年1月1日)
瓦尔福德日=31
val instants=r.instants(from,from.plusDays(forDays.toLong()).toList()
assertEquals(星期日、瞬间、大小)
(1.星期日)forEach{
assertEquals(from.plusDays(it.toLong()-1).atStartOfDay(),instants[it-1])
}
}
}
如果我通过构建一个
ArrayList
来重新实现,它将按预期工作:

// new collection-based methods in Recurrence
    fun instantsList(
        fromInclusive: LocalDate = LocalDate.now(),
        toExclusive: LocalDate = fromInclusive.plusMonths(1)
    ): List<LocalDateTime> = instantsList(fromInclusive.atStartOfDay(), toExclusive.atStartOfDay())

    fun instantsList(
        fromInclusive: LocalDateTime = LocalDateTime.now(),
        toExclusive: LocalDateTime = fromInclusive.plusMonths(1)
    ): List<LocalDateTime> {
        val list = arrayListOf<LocalDateTime>()
        var it = cron.next(fromInclusive.minusNanos(1))
        while (it !== null) {
            if (it.isBefore(toExclusive)) {
                list.add(it)
                it = cron.next(it)
            } else {
                break
            }
        }
        return list
    }

为什么基于序列的实现比基于列表的实现多返回一个元素?

如果我正确阅读了您的代码,那么在列表实现中,您将检查它是否
it.isBefore(toExclusive)
,然后才将其添加到列表中。在序列实现中,执行相同的检查
it.isBefore(toExclusive)
,然后将next项添加到序列中

与第一项类似。在列表实现中,检查cron.next(fromInclusive.minusNanos(1))是否符合要求。在序列实现中,您总是添加它。

谢谢,@broot--您发现了这个问题。刚刚又拍了一组眼球。正确的序列实现是必要的

有趣的瞬间(
fromInclusive:LocalDateTime=LocalDateTime.now(),
toExclusive:LocalDateTime=fromInclusive.plusMonths(1)
):顺序{
val seed=cron.next(fromInclusive.minusNanos(1))
返回生成序列(种子){
val next=cron.next(it)
if(next.isBefore(toExclusive)){
下一个
}否则{
无效的
}
}
}

你发现了。正确的序列实现是'fun instants(fromInclusive:LocalDateTime=LocalDateTime.now(),toExclusive:LocalDateTime=fromInclusive.plusMonths(1)):序列{val seed=cron.next(fromInclusive.minusNanos(1))返回generateSequence(seed){val next=cron.next(it),如果(next.isBefore(toExclusive)){next}else{null}`OMG注释中没有代码格式。呃。我将添加一个答案。请注意,此解决方案与列表实现仍然不同,因为在将其添加到序列之前未检查
种子
。我不知道是否需要此检查。您还可以将
generateSequence()
的正文缩短很多:
cron.next(it).takeIf{it.isBefore(toExclusive)}
。此外,我不确定您是否有意选择使用
generateSequence()
这需要提供一个
nextFunction
,或者您没有注意到有其他方法可以创建序列。如果您对列表实现感到满意,那么它也可以使用几乎1:1来创建序列。只需使用
sequence{}
而不是
generateSeSequence{}
并用
yield()
替换
list.add()
:白色\u复选标记: