在scala

时间:2017-07-07 07:14:05

标签: scala

我有一个要求,我必须在向量的向量中搜索一个字符。我写了一个很粗糙的方法。什么是在向量矢量中搜索元素的更好方法。

这是我的代码:

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 个答案:

答案 0 :(得分:3)

也许是这样的事情?

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

要解决注释中的问题:这是多次遍历整个列表(甚至不是一次完整,只要它早先找到匹配)。 Scala迭代器非常精彩:你可以编写一系列调用,它在概念上看起来像是对整个列表的一系列顺序转换,但实际上是逐个元素地执行:第一个元素是从列表中提取,转换为一个元组(chars, 0),被馈送到map,然后结果被发送到collectFirst,如果条件匹配那里,它会停止并立即返回,否则,下一个元素被采用从列表中,制作成元组(chars, 1),馈送到.map等等......

答案 1 :(得分: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)
}

这假设您只需要该角色的第一次出现。

只要innerIndex大于-1,

indexWhere就会终止。

也许是另一种可能性,它在你的递归方向上更多(并且没有可变的var),但也有最小的迭代次数:

@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)
    }
}