scala - 在 Scala 中将命令式 for 循环重写为声明式样式

标签 scala loops functional-programming tail-recursion declarative

如何使用内置的高阶函数或尾递归将以下循环(模式)重写为 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/

相关文章:

java - Scala 相当于 java.util.stream

scala - 是否存在对无限元素流应用单一变换的双重模式?

Scala -> 函数

python - 比较列表列表中的元素

javascript - 在功能上创建一个位置数组(使用 Underscore/Lodash)

scala - 如何在IDEA上运行scala类

php - fatal error : Call to a member function prepare() on a non-object

python - 如何关闭 while 循环然后执行另一个代码块? while 循环总是重复

scala - 是否有任何记录在案的函数式编程反模式?

PHP 与 array_filter 相反?