如何解决为什么 Kotlin 的 generateSequence 在下面的示例中返回了太多项?
我正在根据 cron 表达式计算瞬间的投影,并将它们作为 Sequence
返回。这是课程:
// (package omitted)
import org.springframework.scheduling.support.CronExpression
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.zoneddatetime
import java.time.temporal.ChronoUnit
class Recurrence(val cronExpression: String) {
private val cron = CronExpression.parse(cronExpression)
fun instants(
fromInclusive: LocalDate = LocalDate.Now(),toExclusive: LocalDate = fromInclusive.plusMonths(1)
): Sequence<LocalDateTime> = instants(fromInclusive.atStartOfDay(),toExclusive.atStartOfDay())
fun instants(
fromInclusive: LocalDateTime = LocalDateTime.Now(),toExclusive: LocalDateTime = fromInclusive.plusMonths(1)
): Sequence<LocalDateTime> {
return generateSequence(cron.next(fromInclusive.minusNanos(1))) {
if (it.isBefore(toExclusive)) {
cron.next(it)
} else {
null
}
}
}
}
以下测试失败,因为第一个断言为假:返回的列表末尾有一个额外的、意外的元素。
// (package omitted)
import java.time.LocalDate
import java.time.Month
import kotlin.test.Test
import kotlin.test.assertEquals
class RecurrenceTest {
@Test
fun testInstants() {
val r = Recurrence("@daily")
val from = LocalDate.of(2021,Month.JANUARY,1)
val forDays = 31
val instants = r.instants(from,from.plusDays(forDays.toLong())).toList()
assertEquals(forDays,instants.size)
(1..forDays).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
}
测试中要更改的一行是使用新方法:
val instants = r.instantsList(from,from.plusDays(forDays.toLong()))
为什么基于序列的实现比基于列表的实现多返回一个元素?
解决方法
如果我正确阅读了您的代码,则在列表实现中您检查是否 it.isBefore(toExclusive)
,然后才将其添加到列表中。在序列实现中,您执行相同的检查 it.isBefore(toExclusive)
,然后将 next 项添加到序列中。
与第一项类似。在列表实现中,您检查 cron.next(fromInclusive.minusNanos(1))
是否满足要求。在顺序实现中,您总是添加它。
谢谢,@broot——你发现了这个问题。刚刚又拍了一组眼球。正确的序列实现是
fun instants(
fromInclusive: LocalDateTime = LocalDateTime.now(),toExclusive: LocalDateTime = fromInclusive.plusMonths(1)
): Sequence<LocalDateTime> {
val seed = cron.next(fromInclusive.minusNanos(1))
return generateSequence(seed) {
val next = cron.next(it)
if (next.isBefore(toExclusive)) {
next
} else {
null
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。