用可变变量写while循环的功能方法

pla*_*oom 2 functional-programming scala

我需要获得一个应该在某些输入和之间填充日期时间间隔的集合LocalDatetime.now.

例:

如果我要建立一个基于每30分钟的间隔,它应该是这样的2017-06-12 00:30, 2017-06-12 01:00, 2017-06-12 01:30, 2017-06-12 02:00..and go on.

我编写了一个符合我要求的代码,但它看起来像是使用Scala语法的Java - 而不是一种功能更清晰的方式.

  val now = LocalDateTime.now
  val dates = if (interval.toInt > 0) {
    var tempDate = LocalDate.now.atStartOfDay()
    val allDates = scala.collection.mutable.ListBuffer[String]()
    while (tempDate.isBefore(now)) {
      allDates += tempDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
      tempDate = tempDate.plusMinutes(interval.toInt)
    }
    allDates
  } else {
    var initialDay = LocalDate.now.minusDays(30)
    val allDates = scala.collection.mutable.ListBuffer[String]()
    while (initialDay.isBefore(LocalDate.now)) {
      allDates += initialDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
      initialDay = initialDay.plusDays(1)
    }
    allDates
  }
Run Code Online (Sandbox Code Playgroud)

如何重构此代码看起来像功能样式或至少删除该可变变量?

Yaw*_*war 6

您应该使用Scala的Stream类型从开始日期以半小时为增量构建一个惰性流,然后懒得只从早于停止日期的日期中获取尽可能多的日期.例如:

def halfHoursFrom(start: LocalDateTime): Seq[LocalDateTime] =
  Stream
    .iterate(start)(_.plusMinutes(30))
    .takeWhile(_.isBefore(LocalDateTime.now))
Run Code Online (Sandbox Code Playgroud)

您将Stream在标准库参考中找到该类型的文档.我们在这里使用的两个值得注意的方法是:

  • Stream.iterate(在Stream伴随对象中):从起始值和增量函数中懒惰地构建无限流
  • Stream#takeWhile(在Stream类中):只从给定流中获取与给定谓词匹配的元素(测试每个元素并返回true/的函数false).

请注意,我正在向上转换返回类型Seq[LocalDateTime]以隐藏调用方的实现细节.

  • 这是一个很好的答案.当我开始使用Scala时,我只会添加一个让我绊倒的提示:Stream被懒惰地评估,但它会缓存它已计算的所有元素,因此它可能会耗尽内存.因此,当替换while循环+可变var时,此模式不总是*适用,因为如果不在每次迭代中收集结果,它可能导致更糟的内存使用.如果你不想保存每次迭代的中间结果,那么`Iterator.iterate`是一个不以这种方式使用内存的等价物. (2认同)