让我们从以下简单的实现开始:
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 的实现中抛出异常),而是使用var
and while
。对于这么简单的事情,这是一件非常合理的事情——只要确保将所有可变状态包装在方法中即可。
朝着更实用的方向迈出的下一步是尝试完全避免使用索引 - 通常可以以您不需要它们的方式重新构建问题,这样做通常会使您的程序更优雅(如果不是更高性能)。