2013-05-07 40 views
4

假设我想查找2D矢量中第一次出现元素的索引。indexOf for Scala中的2D矢量

val table = Vector.tabulate(10, 10)((x,y) => 10*x + y) 
val row = table indexWhere (_.indexOf(42) != -1) // row = 4 
val col = 
    if(row == -1) -1 
    else table(row) indexOf 42 // col = 2 

由于indexOf在包含该元素的行上被调用两次,这看起来有点低效。有没有更好的方式来做到这一点,而不必诉诸于命令式的代码?

回答

6

这不仅效率低下,而且也是危险的。如果我们稍微修改它会怎样?

val row = table indexWhere (_.indexOf(101) != -1) 
val col = table(row) indexOf 42 //Uh-oh, IndexOutOfBounds! 

这似乎真的适合于用于表达:

val z = 
    for { 
    i <- 0 until table.length 
    j <- 0 until table(i).length 
    if (table(i)(j) == 42) 
    } yield (i, j) 

z.headOption.getOrElse(-1, -1) 

这可能是太迫切,但是这一切又在引擎盖下转化为flatMapfilter。你可以用它写,但是这样更具可读性。

编辑:如果您想快速失败行为,递归解决方案将适合该法案:

def findElement(table: Vector[Vector[Int]], elem: Int): (Int, Int) = { 
    @tailrec 
    def feRec(row: Int, col: Int): (Int, Int) = { 
    if (row == table.length) (-1, -1) 
    else if (col == table(row).length) feRec(row + 1, 0) 
    else if (table(row)(col) == elem) (row, col) 
    else feRec(row, col + 1) 
    } 
    feRec(0, 0) 
} 
+0

啊,对了,忘了缺失的元素。尽管如此,不管这个表中的每一个元素都是如此,不管第一场比赛被发现多快? – servechilledorhot 2013-05-07 05:10:09

+0

@ChrisCano是的,它会经过桌子的每一个元素,所以在第一次出现时就不会停下来。 – Yuushi 2013-05-07 05:43:05

+1

您可以将第一个条件更改为“我< - (0,直到table.length).toStream”以使其懒惰并在第一次匹配时停止。 – 2013-05-07 06:00:05