如何使用内置的高阶函数或尾递归将以下循环(模式)重写为 Scala?
这是迭代模式的示例,您可以在其中对两个列表元素进行计算(例如比较),但前提是第二个元素在原始输入中的第一个元素之后。注意这里用的是+1步,但一般情况下可以是+n。
public List<U> mapNext(List<T> list) {
List<U> results = new ArrayList();
for (i = 0; i < list.size - 1; i++) {
for (j = i + 1; j < list.size; j++) {
results.add(doSomething(list[i], list[j]))
}
}
return results;
}
到目前为止,我已经在 Scala 中提出了这个:
def mapNext[T, U](list: List[T])(f: (T, T) => U): List[U] = {
@scala.annotation.tailrec
def loop(ix: List[T], jx: List[T], res: List[U]): List[U] = (ix, jx) match {
case (_ :: _ :: is, Nil) => loop(ix, ix.tail, res)
case (i :: _ :: is, j :: Nil) => loop(ix.tail, Nil, f(i, j) :: res)
case (i :: _ :: is, j :: js) => loop(ix, js, f(i, j) :: res)
case _ => res
}
loop(list, Nil, Nil).reverse
}
编辑:
对于所有贡献者,我只希望我能接受每个答案作为解决方案:)
最佳答案
复出尝试:
在删除我第一次尝试给出答案后,我对其进行了更多思考,并提出了另一个至少更短的解决方案。
def mapNext[T, U](list: List[T])(f: (T, T) => U): List[U] = {
@tailrec
def loop(in: List[T], out: List[U]): List[U] = in match {
case Nil => out
case head :: tail => loop(tail, out ::: tail.map { f(head, _) } )
}
loop(list, Nil)
}
我还想推荐丰富我的库模式,以便将 mapNext 函数添加到 List api(或对任何其他集合进行一些调整)。
object collection {
object Implicits {
implicit class RichList[A](private val underlying: List[A]) extends AnyVal {
def mapNext[U](f: (A, A) => U): List[U] = {
@tailrec
def loop(in: List[A], out: List[U]): List[U] = in match {
case Nil => out
case head :: tail => loop(tail, out ::: tail.map { f(head, _) } )
}
loop(underlying, Nil)
}
}
}
}
然后你可以使用如下函数:
list.mapNext(doSomething)
同样,有一个缺点,因为连接列表相对昂贵。
然而,用于理解的变量赋值也可能非常低效(正如 dotty Scala Wart: Convoluted de-sugaring of for-comprehensions 的这项改进任务所暗示的那样)。
更新
现在我陷入了这个,我简直不能放手:(
关于“请注意,此处使用了 +1 步骤,但一般而言,它可以是 +n。”
我用一些参数扩展了我的建议以涵盖更多情况:
object collection {
object Implicits {
implicit class RichList[A](private val underlying: List[A]) extends AnyVal {
def mapNext[U](f: (A, A) => U): List[U] = {
@tailrec
def loop(in: List[A], out: List[U]): List[U] = in match {
case Nil => out
case head :: tail => loop(tail, out ::: tail.map { f(head, _) } )
}
loop(underlying, Nil)
}
def mapEvery[U](step: Int)(f: A => U) = {
@tailrec
def loop(in: List[A], out: List[U]): List[U] = {
in match {
case Nil => out.reverse
case head :: tail => loop(tail.drop(step), f(head) :: out)
}
}
loop(underlying, Nil)
}
def mapDrop[U](drop1: Int, drop2: Int, step: Int)(f: (A, A) => U): List[U] = {
@tailrec
def loop(in: List[A], out: List[U]): List[U] = in match {
case Nil => out
case head :: tail =>
loop(tail.drop(drop1), out ::: tail.drop(drop2).mapEvery(step) { f(head, _) } )
}
loop(underlying, Nil)
}
}
}
}
关于scala - 在 Scala 中将命令式 for 循环重写为声明式样式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45524615/