14

我想在Scala中递归地反转列表列表。

我在 Python 中编写了这样的深度列表反转:

def deepReverse(items):
    if type(items) == list:
        return [deepReverse(item) for item in reversed(items)]
    else: 
        return items

我将如何在 Scala 中做同样的事情?问题不在于算法 - 它是类型的东西,我比较新。

我需要该函数将 [T] 列表或 List[List[T]] 或 T 列表和 T 列表获取到任意深度。我尝试根据我在其他地方看到的示例制作一个案例类来做到这一点。我不想要一个只返回 Any 并接受 Any 的函数;感觉就像在作弊。

case class NL[+T](val v : Either[List[NL[T]],T])

尽管如此,我还是无法完全平衡我的类型。我是 Scala 的新手,但我认为这将是一个处理递归和打字的绝佳机会。

4

2 回答 2

17

实际上,编写 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)

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
  }
}

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

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)

正如预期的那样。


我应该补充一点,在这种情况下,以下是一个更常见的习语,用于正确获取隐式:

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._

如果我们只是在同一级别编写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)(_ + _))

对两者进行优先级排序的标准方法是将较低优先级隐含在特征 ( ) 中,将另一个隐含在扩展该特征WhateverLow的对象 ( ) 中。WhateverHigh但是,在这样一个相当简单的情况下,在我上面的方法中使用默认参数技巧会更简洁(在我看来也更清晰)rev。但是您更有可能在其他人的代码中看到其他版本。

于 2012-09-28T23:44:29.600 回答
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))
}

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

于 2012-09-28T23:11:25.443 回答