【问题标题】:How to convert an imperative double for-loop to functional style without return in Scala?如何在 Scala 中将命令式双 for 循环转换为函数式而不返回?
【发布时间】:2014-11-02 21:50:12
【问题描述】:

我有以下 Scala 代码,命令式风格,我想知道是否有类似的函数式风格避免使用 return

def function(c: Char, vector: Vector[Vector[Char]]): (x:Int , y:Int) = {
  for (x <- vector.indices)
    for (y <- vector(x).indices)
      if (vector(x)(y) == c)
        return (x, y)
  throw new NoSuchElementException
}

我想知道是否有替代方法,与此方法一样有效,但不使用 return

【问题讨论】:

    标签: scala for-loop functional-programming imperative-programming


    【解决方案1】:

    让我们从以下简单的实现开始:

    def function(c: Char, levelVector: Vector[Vector[Char]]): Option[(Int, Int)] = (
      for {
        (row, x) <- levelVector.zipWithIndex
        (cell, y) <- row.zipWithIndex
        if cell == c
      } yield (x, y)
    ).headOption
    

    (请注意,我在 Option 中返回值,而不是在不匹配的情况下抛出异常,但如果您想要原始行为,可以添加 .getOrElse(throw new NoSuchElementException)。)

    这种实现在很多情况下可能都很好,但是有点浪费,因为它创建了很多中间集合,并且即使在找到匹配项之后也会检查每个元素。 (值得注意的是,您的命令式实现也创建了中间集合,但它们只是范围,而且还没有这种天真的函数式实现那么糟糕。)

    以下版本可能会更高效,但仍然避免return

    def function(c: Char, levelVector: Vector[Vector[Char]]): Option[(Int, Int)] =
      levelVector.view.zipWithIndex.map {
        case (row, x) => (x, row.indexOf(c))
      }.collectFirst {
        case (x, y) if y >= 0 => (x, y)
      }
    

    这里我们使用view 来避免创建一堆中间集合,并使用collectFirst 在找到匹配项后停止检查。

    如果你知道这个方法的性能真的很重要(它可能不是),你仍然应该避免return(这涉及在Scala的实现中抛出异常),而是使用varwhile。对于这么简单的事情,这是一件非常合理的事情——只需确保将所有可变状态封装在方法中即可。

    更多功能方向的下一步是尝试完全避免使用索引 - 通常可以以您不需要它们的方式重新构建问题,这样做通常会使您的程序更优雅(如果不是更高性能的话)。

    【讨论】:

    • 谢谢,我不知道 collectFirst 这就是我要找的东西
    猜你喜欢
    • 2015-06-16
    • 2015-06-01
    • 1970-01-01
    • 2020-07-16
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多