2013-05-07 38 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