延迟计算列表中的项目,直到找到所需的元素
Lazy computation of items in list until required element is found
我正在努力让这个需求尽可能高效,因为它是组合问题求解器的一部分,所以每一点点滴都有助于实现宏伟的计划。
假设我有一个元素列表,在本例中称为转换。
val possibleTransitions : List[Transition] = List[...] //coming from somewhere
我想对每个转换执行(有点昂贵)计算,以获得另一个对象,在本例中称为 State
。
我最自然的做法是使用 for-comprehension
或 map
。前者对我来说更方便,因为我想过滤掉一些不相关的State
对象,比如之前已经处理过的对象。
val newStates = for {
transition <- possibleTransitions
state <- computeExpensiveOperation(transition)
if (confirmNewState(state))
} yield state
State
包含一个值,我们称它为 value()
,它表示该状态的某种吸引力。如果 value()
非常低(有吸引力),我想丢弃列表的其余部分并使用它。由于 possibleTransitions
可能是一个很长的列表(数千),理想情况下我会避免这样做 computeExpensiveOperation
如果例如第一个 State
对象已经有我想要的 value()
。
另一方面,如果我没有找到任何有吸引力的项目 value()
,我想保留 所有 并将它们添加到另一个列表。
val newPending = pending ++ newStates
我试图为此使用 Stream
,以避免在处理它们之前计算所有值。如果我使用 find()
并且我没有找到所需的项目,那么我将无法在流中获取项目(因为它使用一次)。
目前我唯一能看到的可能是在 for-comprehension
中使用 possibleItems.toStream()
并创建另一个集合,一个接一个地遍历每个项目,直到找到该项目(和丢弃集合)或否(并将集合与所有项目一起使用)。
我是否缺少一些更聪明、更有效的方法来做到这一点?
我会使用惰性视图并将它们转换为流来缓存中间结果,然后您可以获得所需的信息:
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。
在计算新的挂起元素时,我们可以将此流附加到挂起。 (顺便说一下:pending应该是一个Queue)
我正在努力让这个需求尽可能高效,因为它是组合问题求解器的一部分,所以每一点点滴都有助于实现宏伟的计划。
假设我有一个元素列表,在本例中称为转换。
val possibleTransitions : List[Transition] = List[...] //coming from somewhere
我想对每个转换执行(有点昂贵)计算,以获得另一个对象,在本例中称为 State
。
我最自然的做法是使用 for-comprehension
或 map
。前者对我来说更方便,因为我想过滤掉一些不相关的State
对象,比如之前已经处理过的对象。
val newStates = for {
transition <- possibleTransitions
state <- computeExpensiveOperation(transition)
if (confirmNewState(state))
} yield state
State
包含一个值,我们称它为 value()
,它表示该状态的某种吸引力。如果 value()
非常低(有吸引力),我想丢弃列表的其余部分并使用它。由于 possibleTransitions
可能是一个很长的列表(数千),理想情况下我会避免这样做 computeExpensiveOperation
如果例如第一个 State
对象已经有我想要的 value()
。
另一方面,如果我没有找到任何有吸引力的项目 value()
,我想保留 所有 并将它们添加到另一个列表。
val newPending = pending ++ newStates
我试图为此使用 Stream
,以避免在处理它们之前计算所有值。如果我使用 find()
并且我没有找到所需的项目,那么我将无法在流中获取项目(因为它使用一次)。
目前我唯一能看到的可能是在 for-comprehension
中使用 possibleItems.toStream()
并创建另一个集合,一个接一个地遍历每个项目,直到找到该项目(和丢弃集合)或否(并将集合与所有项目一起使用)。
我是否缺少一些更聪明、更有效的方法来做到这一点?
我会使用惰性视图并将它们转换为流来缓存中间结果,然后您可以获得所需的信息:
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。
在计算新的挂起元素时,我们可以将此流附加到挂起。 (顺便说一下:pending应该是一个Queue)