2017-07-07 140 views
0

搜索字符向量矢量更好的辦法我有一個要求,我有載體的載體來搜索一個字符。我寫了一個非常粗糙的方法。在矢量矢量中搜索元素的更好方法是什麼?斯卡拉

這裏是我的代碼:

def search(xs: Vector[Vector[Char]], char: Char, rowIndex: Int): Pos = xs.headOption match { 
    case None => Pos(-1, -1) 
    case Some(row) => { 
    val tuple = searchHelper(row, char, 0) 
    if(tuple._1) 
     Pos(rowIndex, tuple._2) 
    else 
     search(xs.tail, char, rowIndex +1) 
    } 
} 

def searchHelper(xs: Vector[Char], char: Char, colIndex: Int): (Boolean, Int) = xs.headOption match { 
    case None => (false, colIndex) 
    case Some(col) => 
    if(col == char) 
     (true, colIndex) 
    else 
     searchHelper(xs.tail, char, colIndex +1) 
} 

search(vector, c, 0) 

這裏是輸入:

val input = 
    """ooo------- 
    |oSoooo---- 
    |ooooooooo- 
    |-ooooooooo 
    |-----ooToo 
    |------ooo-""".stripMargin 

val vector = 
    Vector(input.split("\n").map(str => Vector(str: _*)): _*) 

val c = 'S' 
+2

我認識了Coursera分配,所以我不打算給直行的答案,但是請注意,您正在尋找2個不同的索引值:行索引和列索引。 [標準庫](http://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html)提供了一些從集合中提取索引的不同方法。使用其中的2個(如評論提示中提到的)findChar()挑戰可以用2行代碼解決。 – jwvh

+0

謝謝,我只是需要提示。 – kromastorm

回答

2

如果有更好的,你的意思是更簡潔,你可以嘗試利用上Scalas收集方法:

def search(xs: Vector[Vector[Char]], c: Char): (Int, Int) = { 
    var innerIndex = -1 
    val outerIndex = xs.indexWhere { inner => 
     innerIndex = inner.indexOf(c) 
     innerIndex > -1 
    } 
    (outerIndex, innerIndex) 
} 

這是假設你只需要該字符第一次出現的。

indexWhere儘快終止作爲innerIndex比-1大。

也許另一種可能性,肚裏更在你的遞歸方向(並且沒有一個可變的變量),而且還以最小的迭代:

@tailrec 
def search(xs: Vector[Vector[Char]], c: Char, n: Int = 0): (Int, Int) = { 
    if (n > xs.size - 1) (-1, -1) 
    else 
    xs(n).indexOf(c) match { 
     case -1 => search(xs, c, n + 1) 
     case i => (n, i) 
    } 
} 
+0

謝謝。我會試着理解這段代碼並創建我自己的版本。 – kromastorm

+0

新變形瓦爾! – Dima

+0

@Dima 1.隨意建議一個更好的選項來獲取innerIndex或提供另一個答案。 2.沒有任何狀態泄漏出來,所以我沒有看到這個問題。 – thwiegan

2

這樣的事情,也許?

xs 
.iterator 
.zipWithIndex 
.map { case (chars, idx) => (chars, idx, chars.indexOf(c)) } 
.collectFirst { 
    case (chars, outer, inner) if(inner >= 0) => Pos(outer, inner) 
}.getOrElse(Pos(-1, 1)) 

爲了解決從評論的關注:這是通過整個列表多次迭代(一次也沒有完全的,只要找到一個匹配更早)。 Scala迭代器很奇妙:你可以編寫一個調用鏈,它在概念上看起來像是整個列表中的一系列連續變換,但實際上是逐個元素地執行:第一個元素是從列表中提取的,轉換爲一個元組(chars, 0),供給到map,則該結果被髮送到collectFirst,如果條件有匹配,則停止並返回馬上,否則,下一個元素是從列表中取出,製作成一個元組(chars, 1),供給到.map等..

+0

您正在迭代完整的外部向量(兩次)+您正在尋找每個內部向量中的字符。然後你再次遍歷外部矢量,直到找到匹配。有一個原因,我爲什麼用indexWhere和一個可變的var來做到這一點;)減少迭代次數。 – thwiegan

+1

不,我不是遍歷一個完整的向量。不是兩次,甚至沒有一次。這就是'iterator'調用的目的。 Scala迭代器很懶。所以,不,仍然沒有理由可變狀態;)技術上'.iterator'在這裏甚至是不必要的('zipWithIndex'已經返回一個迭代器),我只是在那裏明確表示所有迭代都是惰性的。 – Dima

+0

好吧,我的壞。你確定zipWithIndex正在返回一個迭代器嗎? Scala repl返回爲我編制索引的整個向量。 – thwiegan