Scala中嵌套列表的深度反转

Gri*_*tty 14 recursion scala list

我想在Scala中以递归方式反转列表列表.

我在Python中编写了深度列表反转,如下所示:

def deepReverse(items):
    if type(items) == list:
        return [deepReverse(item) for item in reversed(items)]
    else: 
        return items
Run Code Online (Sandbox Code Playgroud)

我如何在Scala中完成相同的操作?问题不在于算法 - 它是类型的东西,我是新的.

我需要函数将[T]或List [List [T]]的列表,或T的列表和Ts列表,任意深度.我尝试根据我在其他地方看到的一个例子来创建一个案例类.我不想要一个只返回Any并接受Any的函数; 感觉像是作弊.

case class NL[+T](val v : Either[List[NL[T]],T])
Run Code Online (Sandbox Code Playgroud)

尽管如此,我还是无法让我的类型得到平衡.我是Scala的新手,但我认为这是一个混乱递归和打字的绝佳机会.

Tra*_*own 16

实际上编写sschaef建议的类型类方法的版本并不太难,它将适用于任意嵌套列表:

trait Reverser[C] {
  def reverse(xs: C): C
}

implicit def rev[A](implicit ev: Reverser[A] = null) = new Reverser[List[A]] {
  def reverse(xs: List[A]) =
    Option(ev).map(r => xs map r.reverse).getOrElse(xs).reverse
}

def deepReverse[A](xs: A)(implicit ev: Reverser[A]): A = ev.reverse(xs)
Run Code Online (Sandbox Code Playgroud)

ev我们rev方法中的隐式参数是证明它A本身是可逆的,如果ev是null则意味着它不是.如果我们有A可逆的证据,我们用它来反转我们的元素List[A](这是map正在做的),然后我们反转列表本身.如果我们没有这个证据(getOrElse案例),我们可以撤销列表.

我们可以写rev一点不那么简洁(但可能更具性能),如下所示:

implicit def rev[A](implicit ev: Reverser[A] = null) = if (ev == null) {
  new Reverser[List[A]] {
    def reverse(xs: List[A]) = xs.reverse
  }
} else {
  new Reverser[List[A]] {
   def reverse(xs: List[A]) = (xs map ev.reverse).reverse
  }
}
Run Code Online (Sandbox Code Playgroud)

要测试这两个版本中的任何一个,我们可以编写以下内容:

scala> deepReverse(List.tabulate(3)(identity))
res0: List[Int] = List(2, 1, 0)

scala> deepReverse(List.tabulate(2,3) { case (a, b) => a + b })
res1: List[List[Int]] = List(List(3, 2, 1), List(2, 1, 0))

scala> deepReverse(List.tabulate(2, 3, 4, 5, 6) {
     |   case (a, b, c, d, e) => a + b + c + d + e
     | }).head.head.head.head
res2: List[Int] = List(15, 14, 13, 12, 11, 10)
Run Code Online (Sandbox Code Playgroud)

正如所料.


我应该补充一点,以下是一个更常见的习惯用法,可以在这种情况下获得正确的含义:

trait ReverserLow {
  implicit def listReverser[A] = new Reverser[List[A]] {
    def reverse(xs: List[A]) = xs.reverse
  }
}

object ReverserHigh extends ReverserLow {
  implicit def nestedListReverser[A](implicit ev: Reverser[A]) =
    new Reverser[List[A]] {
      def reverse(xs: List[A]) = xs.map(ev.reverse).reverse
    }
}

import ReverserHigh._
Run Code Online (Sandbox Code Playgroud)

如果我们刚刚编写listReversernestedListReverser处于同一级别,当我们尝试反转列表列表时,我们会收到以下错误:

scala> deepReverse(List.tabulate(2, 3)(_ + _))
<console>:12: error: ambiguous implicit values:
 both method listReverser...
 and method nestedListReverser...
 match expected type Reverser[List[List[Int]]]
              deepReverse(List.tabulate(2, 3)(_ + _))
Run Code Online (Sandbox Code Playgroud)

确定二者优先级的标准方法是将较低优先级隐含在trait(WhateverLow)中,将另一个隐含在WhateverHigh扩展该特征的object()中.但是,在这样一个相当简单的情况下,在我rev上面的方法中使用默认参数技巧更简洁(更清晰,在我看来).但是你更有可能在其他人的代码中看到其他版本.


kir*_*uku 5

如果你想要这个真正的类型安全,那么类型类型模式是你的朋友:

object Reverse extends App {

  trait Reverser[C] {
    def reverse(xs: C): C
  }

  implicit def List1Reverser[A] = new Reverser[List[A]] {
    def reverse(xs: List[A]) =
      xs.reverse
  }

  implicit def List2Reverser[A] = new Reverser[List[List[A]]] {
    def reverse(xs: List[List[A]]) =
      xs.map(_.reverse).reverse
  }

  implicit def List3Reverser[A] = new Reverser[List[List[List[A]]]] {
    def reverse(xs: List[List[List[A]]]) =
      xs.map(_.map(_.reverse).reverse).reverse
  }

  def deepReverse[A](xs: A)(implicit rev: Reverser[A]): A =
    rev.reverse(xs)

  val xs = List(1,2)
  val xxs = List(List(1,2),List(1,2),List(1,2))
  val xxxs = List(List(List(1,2),List(1,2)),List(List(1,2),List(1,2)),List(List(1,2),List(1,2)))

  println(deepReverse(xs))
  println(deepReverse(xxs))
  println(deepReverse(xxxs))
}
Run Code Online (Sandbox Code Playgroud)

唯一的问题是每个嵌套列表类型都需要一个类型类.