首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用fold进行布尔测试

如何使用fold进行布尔测试
EN

Stack Overflow用户
提问于 2017-10-20 11:14:38
回答 4查看 1K关注 0票数 3

我想知道在scala中解决这个问题的惯用方法。

给定开始日期和结束日期,以及介于两者之间的日期集合,确定给定的日期集合是否包含从开始日期到结束日期的所有必需日期,并且两个日期之间没有间隔日期。

类型签名:

def checkDate(start: DateTime, end: DateTime, between: IndexedSeq[DateTime]): Boolean

要做到这一点,“正常”或“非功能性”的方法应该是这样的:

代码语言:javascript
复制
def checkDate(start: DateTime, end: DateTime, between: IndexedSeq[DateTime]): Boolean = {
  i = 1
  status = true
  while(start != end) {
    d = start.plusDays(i)
    if (!between.contains(d) {
      status = false
      break
    }
    i += 1
  }
  return status
}

我如何使用折叠键来做这件事?

这是我到目前为止的思考过程:

代码语言:javascript
复制
def checkDate(start: DateTime, end: DateTime, between: IndexedSeq[DateTime]): Boolean = {

  // A fold will assume the dates are in order and move left (or right)
  // This means the dates must be sorted.
  val sorted = between.sortBy(_.getMillis())

  val a = sorted.foldLeft(List[Boolean]) {
    (acc, current) => {
      // How do I access an iterable version of the start date?
      if (current == ??) {
        acc :: true
      } else false
    }
  }

  // If the foldLeft produced any values that could NOT be matched
  // to the between list, then the start date does not have an 
  // uninterrupted path to the end date.
  if (a.count(_ == false) > 0) false
  else true
}

我只需要弄清楚如何索引start参数,这样我就可以在fold迭代between集合时增加它的值。也有可能fold根本不是我应该使用的。

任何帮助都将不胜感激!

EN

回答 4

Stack Overflow用户

发布于 2017-10-20 12:51:30

您可以在累加器中传递前一个DateTime项目:

代码语言:javascript
复制
val a = sortedBetween.foldLeft((List[Boolean](), start)) {
  case ((results, prev), current) => {
    ... calculate res here ...
    (results ++ List(res), current)
  }
}

但是对于这种检查,你最好使用sliding和forall组合:

代码语言:javascript
复制
 sortedBetween.sliding(2).forall {
   case List(prev,cur) => ..do the check here ..
 }

另外,请注意,由于IndexedSeq是不可变的,所以您会忽略between排序结果。修复-使用另一个val:

代码语言:javascript
复制
val sortedBetween = between.sortBy(_.getMillis())
票数 3
EN

Stack Overflow用户

发布于 2017-10-20 13:56:51

我认为折叠是不必要的,它使事情变得太难了。

假设您有以下函数:

代码语言:javascript
复制
private def normalizeDateTime( dt : DateTime ) : DateMidnight = ???

private def requiredBetweens( start : DateMidnight, end : DateMidnight ) : Seq[DateMidnight] = ???

然后你可以像下面这样写你的函数:

代码语言:javascript
复制
def checkDate(start: DateTime, end: DateTime, between: IndexedSeq[DateTime]): Boolean = {
   val startDay = normalizeDateTime( start )
   val endDay = normalizeDateTime( end )
   val available = between.map( normalizeDateTime ).toSet
   val required = requiredBetweens( startDay, endDay ).toSet
   val unavailable = (required -- available)
   unavailable.isEmpty
}

请注意,此函数不要求中间元素的顺序,将元素视为一个集合,只要求每天都在某个地方可用。

要实现normalizeDateTime(...),您可能会使用像dt.toDateMidnight这样简单的东西,但您应该考虑一下Chronology和时区问题。您想要表示某一天的DateTime对象始终规范化为相同的DateMidnight,这一点很重要。

要实现requiredBetweens(...),您可以考虑使用StreamtakeWhile(...)作为一个优雅的解决方案。您可能需要该(end isAfter start)

票数 1
EN

Stack Overflow用户

发布于 2017-10-20 14:05:22

我会使用过滤器,然后压缩并取差值,日期应该总是相隔一天,所以检查它们都是1。

代码语言:javascript
复制
@ val ls = Array(1, 2, 3, 4, 5, 6, 7)  // can use dates in the same way
ls: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7)

@ val ls2 = ls.filter { i => (2 < i) && (i < 6) }
ls2: Array[Int] = Array(3, 4, 5)

@ ls2.zip(ls2.drop(1))
res21: Array[(Int, Int)] = Array((3, 4), (4, 5))

@ ls2.zip(ls2.drop(1)).map { case (x, y) => y-x }
res22: Array[Int] = Array(1, 1)

@ ls2.zip(ls2.drop(1)).map { case (x, y) => y-x }.forall { _ == 1 }
res23: Boolean = true

您还必须检查是否没有遗漏日期:

代码语言:javascript
复制
@ ls2.length == 6 - 2 - 1  // beware off-by-one errors
res25: Boolean = true

您也可以通过使用Range对象更简单地完成此操作:

代码语言:javascript
复制
@ ls2.zipAll(3 to 5 by 1, 0, 0).forall { case (x, y) => x == y }
res46: Boolean = true

这应该可以工作,但可能需要对DateTime稍作调整……

代码语言:javascript
复制
@ val today = LocalDate.now
today: LocalDate = 2017-10-19

@ val a = (0 to 9).reverse.map { today.minusDays(_) }
a: collection.immutable.IndexedSeq[LocalDate] = Vector(2017-10-10, 2017-10-11, 2017-10-12, 2017-10-13, 2017-10-14, 2017-10-15, 2017-10-16, 2017-10-17, 2017-10-18, 2017-10-19)

@ a.zip(a.drop(1)).map { case (x, y) => x.until(y) }.forall { _ == Period.ofDays(1) }
res71: Boolean = true
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46841897

复制
相关文章

相似问题

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