如何在Scala中将命令式双循环转换为函数式而无需返回?

时间:2014-11-02 21:50:13

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

我有以下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的情况下,是否有替代方案,效率与此相同。

1 个答案:

答案 0 :(得分:2)

让我们从以下天真实施开始:

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。对于这个简单的事情来说,这是非常合理的事情 - 只要确保你在方法中包含所有可变状态。

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