2017-07-07 99 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