【问题标题】:Recursively handle nested lists in scala递归处理scala中的嵌套列表
【发布时间】:2017-01-13 08:11:48
【问题描述】:

我正在自学 scala 并努力提高我的 FP 技能。

我的参考资料之一,编程语言基础 (available here),有一个方便的简单递归函数列表。在第 27/50 页,我们被要求实现 swapper() 函数。

(swapper s1 s2 slist) returns a list the same as slist, but
with all occurrences of s1 replaced by s2 and all occurrences of s2 replaced by s1.


> (swapper ’a ’d ’(a b c d))
(d b c a)
> (swapper ’a ’d ’(a d () c d))
(d a () c a)
> (swapper ’x ’y ’((x) y (z (x))))
((y) x (z (y)))

在 Scala 中,这是:

swapper("a", "d", List("a","b","c","d"))
swapper("a", "d", List("a","d",List(),"c","d"))
swapper("x", "y", List( List("x"), "y", List("z", List("x"))))

我的 scala 版本处理所有版本,除了最后的 x。

def swapper(a: Any, b: Any, lst: List[Any]): List[Any] ={
   def r(subList :List[Any], acc : List[Any]): List[Any] ={
     def swap (x :Any, xs: List[Any]) =
       if(x == a){
         r(xs, acc :+ b)
       } else if (x == b) {
         r(xs, acc :+ a)
       } else {
         r(xs, acc :+ x)
       }
     subList match {
     case Nil =>
       acc
     case List(x) :: xs =>
       r(xs, r(List(x), List()) +: acc)
     case x :: xs =>
       swap(x,xs)
     //case List(x) :: xs =>
   }
   }
  r(lst, List())
}

本能地,我认为这是因为我在“case List(x) :: xs”部分没有交换,但我仍在努力修复它。

更困难的是,这种情况仍然破坏了尾调用优化。我该怎么做?在哪里可以了解有关通用解决方案的更多信息?

【问题讨论】:

    标签: scala recursion functional-programming lisp tail-recursion


    【解决方案1】:

    您可以将此 foldRight 与模式匹配方法一起使用:

    def swapper(a:Any, b:Any, list:List[Any]):List[Any] = 
      list.foldRight(List.empty[Any]) {
        case (item, acc) if item==a => b::acc
        case (item, acc) if item==b => a::acc
        case (item:List[Any], acc) => swapper(a, b, item)::acc
        case (item, acc) => item::acc
      }     
    

    甚至更简单(感谢@marcospereira):

    def swapper(a:Any, b:Any, list:List[Any]):List[Any] = 
      list.map {
        case item if item==a => b
        case item if item==b => a
        case item:List[Any] => swapper(a, b, item)
        case item => item
      }  
    

    【讨论】:

    • 好的!感谢您的洞察力,这肯定会简化事情。虽然添加注释 @tailrec 确实抱怨递归调用不是尾部位置。
    【解决方案2】:

    解决这个问题的更简单方法是使用map

    def swapper[T](a: T, b: T, list: List[T]): List[T] = list.map { item =>
      if (item == a) b
      else if (item == b) a
      else item
    }
    

    【讨论】:

    • 似乎无法处理 OP 的第三个测试用例。
    【解决方案3】:

    这似乎有效。

    def swapper[T](a: T, b: T, lst: List[_]): List[_] = {
      val m = Map[T, T](a -> b, b -> a).withDefault(identity)
      def swap(arg: List[_]): List[_] = arg.map{
        case l: List[_] => swap(l)
        case x: T => m(x)
      }
      swap(lst)
    }
    

    List 元素不一致,因为它可能是一个元素,也可能是另一个 List,因此类型为 List[Any],这无疑是需要有人重新考虑这种数据表示的感叹。

    【讨论】:

      猜你喜欢
      • 2016-06-18
      • 1970-01-01
      • 2017-01-19
      • 1970-01-01
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多