【问题标题】:Optimize solution for the given coding problem针对给定的编码问题优化解决方案
【发布时间】:2021-09-06 10:08:03
【问题描述】:

我是 Scala 的新手,我正在尝试解决以下简单的编码问题:

编写一个 listOfLists 递归方法,将多个字符串作为可变参数,然后 创建一个字符串列表,每个列表少一个字符串,例如: listOfLists("3","2","1") 应该回馈:List(List("3","2","1"), List("2","1"), List("1"))

我找到的解决方案如下:

def listOfLists(strings: String*): List[List[String]] = {
      val strLength = strings.length

      @tailrec
      def recListOfList(result: List[List[String]], accumulator: Int): List[List[String]] = {
          accumulator match {
            case x if x < strLength =>
              recListOfList(result :+ (strings.toList.takeRight(strings.length - accumulator)), accumulator + 1 )
            case _ => result
          }
        }

      val res: List[List[String]] = List(strings.toList)
      recListOfList(res, 1)
}

该解决方案有效,但我认为它可以写得更好。 我可以看到的一个问题是我使用 toList 方法将可变参数转换为 List,但问题给我的提示是使用 eta 扩展 _* 但我不知道如何在这种情况下使用它。

然后,我试图找到另一种更有效的方式来编写以下指令:

strings.toList.takeRight(strings.length - accumulator))

但这是我想到的唯一解决方案。

欢迎任何评论(也说这个解决方案一团糟:D(提供正确的理由))

【问题讨论】:

    标签: list scala recursion optimization


    【解决方案1】:

    从 Scala 2.13 开始,您可以使用 List.unfoldOption.when

    def listOfLists(strings: String*): List[List[String]] = {
      List.unfold(strings) { s =>
        Option.when(s.nonEmpty)(s.toList, s.tail)
      }
    }
    

    代码在Scastie 运行。

    【讨论】:

    • 我猜这个练习是用尾递归来解决的。
    • 感谢@LuisMiguelMejíaSuárez!所以我修改了另一个答案,它可以工作。
    【解决方案2】:

    这符合所有指定的要求。

    def listOfLists(strings: String*): List[List[String]] =
      if (strings.isEmpty) Nil
      else strings.toList :: listOfLists(strings.tail:_*)
    

    【讨论】:

      【解决方案3】:

      你可以这样做:

      def listOfLists(strings: String*): List[List[String]] = {
        @annotation.tailrec
        def loop(remaining: List[String], acc: List[List[String]]): List[List[String]] =
          remaining match {
            case head :: tail =>
              loop(remaining = tail, (head :: tail) :: acc)
            
            case Nil =>
              acc.reverse
          }
        
        loop(remaining = strings.toList, acc = List.empty)
      }
      

      我相信代码是不言自明的;但是,如果您有任何问题,请随时提出。


      可以看到运行here的代码

      【讨论】:

        【解决方案4】:

        使用几乎相同的想法,您可以以更简洁的方式重写您的解决方案:

        def listOfLists(strings: String*): List[List[String]] = {
              @tailrec
              def recListOfList(curr: List[String], accumulator: Seq[List[String]]): Seq[List[String]] = {
                  curr match {
                    case head :: tail => recListOfList(tail, curr +: accumulator)
                    case _ => accumulator
                  }
                }
        
              recListOfList(strings.toList, Nil)
                .reverse
                .toList
        }
        

        使用 splat(_*) 运算符,它将序列(数组、列表、序列、向量等)适应可变参数参数,您可以创建更短的解决方案,但它不会是尾递归的:

        def listOfLists(strings: String*): List[List[String]] = {
          val curr = strings.toList
          curr match {
           case Nil => Nil    
           case x :: tail => curr :: listOfLists(tail:_*)
          }  
        }
        

        【讨论】:

        • ^^ curr :: listOfLists1(tail:_*)
        • @Dima 谢谢,我对解决方案有点抱怨,结果丢失了 =))
        【解决方案5】:

        不是递归方法,但值得注意的是标准库中的tails 可以完成大部分操作。然后映射和过滤以转换为正确的类型并过滤掉空列表。

        def listOfLists(strings: String *): List[List[String]] = strings.tails.map(_.toList).filter(_.nonEmpty).toList
        

        测试:

        scala> listOfLists("a","b","c")
        val res6: List[List[String]] = List(List(a, b, c), List(b, c), List(c))
        

        【讨论】:

        • 最好在tails之前调用toList以避免调用.map(_.toList)
        猜你喜欢
        • 2020-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-03
        相关资源
        最近更新 更多