繁体   English   中英

Scala中嵌套列表的深度反转

[英]Deep-reverse of nested lists in Scala

我想在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的列表和Ts列表,任意深度。 我尝试根据我在其他地方看到的一个例子来创建一个案例类。 我不想要一个只返回Any并接受Any的函数; 感觉像是作弊。

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

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

编写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)

我们的rev方法中隐含的参数ev是证明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方法中使用默认的参数技巧,它更简洁(更清晰,在我看来)。 但是你更有可能在其他人的代码中看到其他版本。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM