在2维scala列表中查找字符

时间:2013-05-15 04:19:06

标签: scala

所以这可能不是解决问题的最佳方法,但我最初的想法是表达。 假设我有一个像

这样的列表
List(List('a','b','c'),List('d','e','f'),List('h','i','j'))

我想找到一个字符的行和列,比如'e'

def findChar(letter: Char, list: List[List[Char]]): (Int, Int) =
  for {
    r <- (0 until list.length)
    c <- (0 until list(r).length)
    if list(r)(c) == letter
  } yield (r, c)

如果有一种更优雅的方式,我会全神贯注,但我也想了解这有什么问题。特别是编译器给我的错误是

type mismatch;  found   : scala.collection.immutable.IndexedSeq[(Int, Int)]  required: (Int, Int)
分配给r的行上的

。似乎抱怨我的迭代器与返回类型不匹配,但我不太明白为什么这是或者该怎么做...

2 个答案:

答案 0 :(得分:2)

对于你的另一只耳朵,问题重复

How to capture inner matched value in indexWhere vector expression?

scala> List(List('a','b','c'),List('d','e','f'),List('h','i','j'))
res0: List[List[Char]] = List(List(a, b, c), List(d, e, f), List(h, i, j))

scala> .map(_ indexOf 'e').zipWithIndex.find(_._1 > -1)
res1: Option[(Int, Int)] = Some((1,1))

答案 1 :(得分:1)

findChar的签名中,您告诉编译器它返回(Int, Int)。但是,您的for表达式(由Scala推断)的结果为IndexedSeq[(Int, Int)],如错误消息所示。原因是(r, c)yield表达式中的每个“迭代”后生成for(即,您生成一系列结果,而不仅仅是单个结果)。

编辑:至于findChar,您可以这样做:

def findChar(letter: Char, list: List[List[Char]]) = {
  val r = list.indexWhere(_ contains letter)
  val c = list(r).indexOf(letter)
  (r, c)
}

这不是最有效的解决方案,但相对较短。

编辑或重复使用您原来的想法:

def findAll(letter: Char, list: List[List[Char]]) =
  for {
    r <- 0 until list.length
    c <- 0 until list(r).length
    if list(r)(c) == letter
 } yield (r, c)

def findChar(c: Char, xs: List[List[Char]]) = findAll(c, xs).head

在这两种情况下,请注意,如果搜索的字母未包含在输入列表中,则会发生异常。

编辑:或者您自己编写递归函数,例如:

def findPos[A](c: A, list: List[List[A]]) = {
  def aux(i: Int, xss: List[List[A]]) : Option[(Int, Int)] = xss match {
    case Nil => None
    case xs :: xss =>
      val j = xs indexOf c
      if (j < 0) aux(i + 1, xss)
      else Some((i, j))
  }
  aux(0, list)
}

其中aux是一个(本地定义的)辅助函数,它执行实际的递归(并记住我们在哪个子列表中,索引i)。在此实现中,None的结果表示搜索的元素不存在,而成功的结果可能返回Some((1, 1))之类的内容。