列表中项目的延迟计算,直到找到所需的元素

时间:2016-02-07 13:00:44

标签: list scala stream for-comprehension

我正在努力让这个要求尽可能高效,因为它是组合问题求解器的一部分,因此每一点点都有助于宏观方案。

假设我有一个元素列表,在这种情况下称为转换。

val possibleTransitions : List[Transition] = List[...] //coming from somewhere

我想对每次转换执行(有点贵)计算,以获得另一个对象,在本例中称为State

我这样做的自然方式是使用for-comprehensionmap。前者对我来说更方便,因为我想过滤掉一些不相关的State对象,例如那些早先已经处理过的对象。

val newStates = for {
     transition <- possibleTransitions
     state <- computeExpensiveOperation(transition)
     if (confirmNewState(state))
} yield state

State包含一个值,我们称之为value(),这表示该状态具有某种吸引力。如果value()非常低(有吸引力),我想丢弃列表的其余部分并使用它。由于possibleTransitions可能是一个非常长的列表(数千个),所以如果第一个computeExpensiveOperation对象已经拥有我想要的State,理想情况下我会避免这样做value()。 p>

另一方面,如果我找不到任何具有吸引力value()的项目,我想保留所有,并将它们添加到另一个列表中。

val newPending = pending ++ newStates

我试图使用Stream来避免在处理它们之前计算所有值。如果我使用find()而我找不到所需的项目,那么我将无法获取流中的项目(因为它使用一次)。

我目前唯一可以看到的是在possibleItems.toStream()中使用for-comprehension并创建另一个集合,逐个遍历每个项目,直到我找到该项目(并丢弃集合)或否(并使用所有项目的集合)。

我错过了一些更聪明,更有效的方法吗?

1 个答案:

答案 0 :(得分:1)

我会使用延迟视图并将它们转换为流来缓存中间结果,然后您可以获得所需的信息:

val newStates = for {
     transition <- possibleTransitions.view
     state <- computeExpensiveOperation(transition)
     if (confirmNewState(state))
} yield state
val newStatesStream = newStates.toStream // cache results

val attractive = newStatesStream.find(isAttractive(_))
attractive match {
  case Some(a) => // do whatever
  case None => {
    val newPending = pending ++ newStatesSteam
  }
}

由于流是惰性的,因此只有在val attractive的行中找到第一个元素时才会计算它。如果没有吸引人的元素,则将计算和缓存完整的流,并且将返回None。

在计算新的待处理元素时,我们可以将此流附加到待处理状态。 (顺便说一句:待定应该是一个队列)