Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

indexOf for 2D Vector in Scala

Tags:

scala

Say I want to find the indices of the first occurrence of an element in a 2D Vector.

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

This seems a tad inefficient, as indexOf gets called twice on the row containing the element. Is there a better way to do this without having to resort to imperative code?

like image 881
servechilledorhot Avatar asked May 07 '13 04:05

servechilledorhot


1 Answers

It's not only inefficient, it's also dangerous. What if we modified it slightly?

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

This really seems suited to a for-expression:

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)

This might be too imperative, but it all gets transformed to flatMap and filter under the hood. You could write it with that, but this is far more readable.

Edit: If you want fail-fast behaviour, a recursive solution will fit the bill:

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)
}
like image 180
Yuushi Avatar answered Oct 04 '22 16:10

Yuushi