在我的命令式Scala代码中,我有一个算法:
def myProcessor(val items: List) {
var numProcessed = 0
while(numProcessed < items.size) {
val processedSoFar = items.size - numProcessed
numProcessed += processNextBlockOfItems(items, processedSoFar)
}
}
我想保留“块处理”功能,而不只是在项目列表上执行“takeWhile”。我怎样才能在功能风格中重写它?
答案 0 :(得分:5)
您需要将其更改为递归样式,其中您在每个循环的“状态”中“通过”
@tailrec
def myProcessor(items: List[A], count: Int = 0): Int = items match{
case Nil => count
case x :: xs =>
processNextBlockOfItems(items, count)
myProcessor(xs, count + 1)
}
假设“processedSoFar”不是索引。如果您可以使用列表的当前“头部”:
@tailrec
def myProcessor(items: List[A], count: Int = 0): Int = items match{
case Nil => count
case x :: xs =>
process(x)
myProcessor(xs, count + 1)
}
其中process
只会处理List
的当前“头部”。
答案 1 :(得分:1)
所以,这取决于你认为更实用的东西,但这里是没有'var'的版本
def myProcessorFunctional(items: List[Int]) {
def myProcessorHelper(items: List[Int], numProcessed: Int) {
if (numProcessed < items.size) {
val processedSoFar = items.size - numProcessed
myProcessorHelper(items,
numProcessed + processNextBlockOfItems(items, processedSoFar))
}
}
myProcessorHelper(items, 0)
}
(为了简单起见,将其列为Ints列表,很容易使其与通用列表一起使用)
我不得不说这是我不介意变量变量的情况之一 - 很明显,没有对它的引用会逃避该方法。
但正如我在上面的评论中所说的那样,processNextBlockOfItems无论如何本质上都是非功能性的,因为它需要它的副作用。一种更实用的方法是它返回到目前为止的处理状态,并且这个状态将在后续调用中更新(并返回)。现在,如果您正在处理两个不同的项目列表,那么您将遇到在processNextBlockOfItems中维护两个不同的部分处理状态的问题......
<强>随后:强>
仍然忽略状态问题,一个方便的改变是如果processNextBlockOfItems总是处理传递给它的项目列表的第一个块,返回它没有处理的剩余项目(如果使用List,这是方便和有效的,所以很多我想知道你为什么要使用指标。
这会产生类似的结果:
def myProcessorMoreFunctional(items: List[Int]) {
if (!items.isEmpty) {
myProcessorMoreFunctional(processNextBlockOfItems(items))
}
}