【问题标题】:scala searching nested arraysscala搜索嵌套数组
【发布时间】:2013-01-18 07:44:00
【问题描述】:

我正在尝试在嵌套的字符数组中搜索特定字符,然后从数组中返回字符的索引。

代码片段

def search(target: Char, arr:Array[Array[Char]]): List[Int] = {
    for (i <- 0 until arr.length) { //search through first layer of array
    for (j <- 0 until arr(i).length) { //search through second layer of array
        if (arr(i)(j) == target) {
            val x = List(i,j)
            return x
        } }}}

但是,我从编译中得到一个错误,说这个函数正在返回两种类型的签名。错误信息:

error: type mismatch;
 found   : Unit
 required: List[Int]
for (i <- 0 until arr.length) { //search through first layer of array
       ^

我在这里找到了两个类似的主题:found Unit: required Int. Why is the error not obvious? 和found: Unit required: Int - How to correct this?

但它们并没有解决我面临的问题:我 am 试图返回列表,但编译器卡在 for 循环中..

【问题讨论】:

    标签: arrays scala search return


    【解决方案1】:

    只有在满足特定条件 (arr(i)(j) == target) 时才会返回 List。您必须为 for 理解运行的情况定义一个返回值。例如

    def search(target: Char, arr:Array[Array[Char]]): List[Int] = {
      for (i <- 0 until arr.length) { //search through first layer of array
        for (j <- 0 until arr(i).length) { //search through second layer of array
          if (arr(i)(j) == target) {
            val x = List(i,j)
            return x
          }
        }
      }
      Nil  // not found
    }
    

    【讨论】:

      【解决方案2】:

      如果第二个数组为空或 if 表达式的计算结果为 false,则 for 循环本身将返回 Unit。你可以重写它,如果它永远不会到达 if 表达式之后的代码,它会返回 null。

      我也会省略 x 的分配,真的没有意义。

        def search(target: Char, arr:Array[Array[Char]]): List[Int] = 
        {
          for (i <- 0 until arr.length) 
          { //search through first layer of array
            for (j <- 0 until arr(i).length) 
            { //search through second layer of array
              if (arr(i)(j) == target) 
              {
                return List(i,j)
              } 
            }
          }
          Nil
        }
      

      顺便说一句,这可能会用更实用的方法重写,但这超出了这个问题的范围。

      【讨论】:

      • 其实就算省略赋值,也不应该省略return,否则循环不会被打断,你的函数会一直返回null。
      【解决方案3】:

      我建议完全使用一种不太像 Java 的方法。我不完全确定你的函数应该做什么,但如果你想要嵌套数组中匹配的所有 (x, y) 索引的列表,你可以这样做:

      def search(target: Char, array: Array[Array[Char]]): Seq[(Int, Int)] = {
        array.zipWithIndex.filter(_._1.contains(target)).map { xa =>
          xa._1.zipWithIndex.filter(_._1 == target).map(xb => (xa._2, xb._2)).toSeq
        }.flatten.toSeq
      }
      

      行为如下:

      val t = Array(
          Array('a', 'b', 'c'), 
          Array('b'), Array('c', 'a'), 
          Array('a', 'a', 'x', 'a')
      )
      println(search('a', t))
      => ((0,0), (2,1), (3,0), (3,1), (3,3))
      

      【讨论】:

        【解决方案4】:

        这是我在二维数组中查找元素的第一个索引的解决方案: (如果要查找所有索引,请替换 collectFirt 来收集)

        def search[T](target: T, arr: Array[Array[T]]): List[Int] = 
          arr.indices.collectFirst{
            case k if arr(k).contains(target) => 
              List(k, arr(k).indexWhere(_ == target)) 
          }.getOrElse(Nil)
        

        测试:

        scala> val t = Array(
             |     Array('a', 'b', 'c'),
             |     Array('b'), 
             |     Array('c', 'a'),
             |     Array('a', 'a', 'x', 'a')
             | )
        
        scala> println(search('a', t))
        List(0, 0)
        
        scala> println(search('x', t))
        List(3, 2)
        
        scala> println(search('e', t))
        List()
        

        【讨论】:

          【解决方案5】:

          似乎已经有很多答案了,但我认为这是解决问题的最惯用的方法:

          守则

          def search(target: Char, arr: Array[Array[Char]]): List[(Int, Int)] = {
          
              val indices = for{
                  (a, i) <- arr.iterator.zipWithIndex
                  (c, j) <- a.iterator.zipWithIndex
                  if( c == target )
              } yield i -> j
          
              indices.toList
          
          }
          

          解释

          在 scala 中,for-comprehensions 是可嵌套的,因此您只需添加另一行 x &lt;- y 即可处理任何程度的嵌套数组。您可以在for{...} 内使用if 语句引入过滤。

          在理解中,a 是arr 内的ith 数组,其中i 是第一个索引。 c 是a 中的jth 字符,其中j 是第二个索引。我使用iterator,以便可以即时评估indices,而无需因为理解而在幕后复制数组。最后,我调用toList 将indices 迭代器的结果评估为一个列表。

          返回类型List[(Int, Int)] 是对的列表。如果您在i=1, j=2 和i=3, j=4 找到目标,则返回List( (1,2), (3,4) ) 比返回List(1,2,3,4) 更有意义。

          一般想法

          尽量避免在 scala 中使用return。您通常可以使用类似迭代器的方法使用 yield 来处理您的集合,然后通过调用 toList 或 toMap 或 toWhatever 来评估结果。

          scala 集合 API 对其中许多情况也很有帮助。如果您只想要第一个匹配条件的项目,您可以使用myCollection.find(...)。浏览 scala 文档,了解您已经可以使用的大量便捷功能。

          【讨论】:

          • +1 可能是最简洁的解决方案(在 Scala 中),但也可能是非 Scala 人员最难以理解的解决方案
          • @Leo 可能是代码本身,但随附的解释非常好,我认为当您深入研究一门语言时,您应该尝试以最惯用的方式学习和编写它。我也认为你应该尽早学习这种方式,这样你才能养成良好的习惯并充分利用这种语言。另一方面,Scala 不是一门很好的初学者语言,它的数学非常优美,与现实非常抽象,大多数人讨厌这一点。我发现它的学习曲线很长,但它的表现力确实在我身上成长。
          猜你喜欢
          • 1970-01-01
          • 2016-01-13
          • 1970-01-01
          • 2022-08-09
          • 2015-06-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多