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)
如果我们刚刚编写listReverser并nestedListReverser处于同一级别,当我们尝试反转列表列表时,我们会收到以下错误:
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上面的方法中使用默认参数技巧更简洁(更清晰,在我看来).但是你更有可能在其他人的代码中看到其他版本.
如果你想要这个真正的类型安全,那么类型类型模式是你的朋友:
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)
唯一的问题是每个嵌套列表类型都需要一个类型类.
| 归档时间: |
|
| 查看次数: |
833 次 |
| 最近记录: |