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