2

我有以下 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.

4

1 回答 1

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 的实现中抛出异常),而是使用varand while。对于这么简单的事情,这是一件非常合理的事情——只要确保将所有可变状态包装在方法中即可。

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

于 2014-11-02T22:24:40.173 回答