2013-05-07 2 views
4

Скажем, я хочу найти индексы первого вхождения элемента в 2D-вектор.indexOf для 2D Vector в Scala

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) 

Это может быть слишком важно, но все это трансформируется в flatMap и filter под капотом. Вы могли бы написать это с этим, но это гораздо более читаемо.

Edit: Если вы хотите, отказоустойчивости быстрого поведения, рекурсивное решение будет соответствовать всем требованиям:

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

+0

@ChrisCano Да, он пройдет через каждый элемент таблицы, поэтому не останавливаться при первом вхождении. – Yuushi

+1

Вы можете изменить первое условие на «i <- (0 до table.length) .toStream», чтобы сделать его ленивым и остановить в первом матче. –

Смежные вопросы