失败解析视图
Failure parsing views
我在 Seq[Int]
上定义了以下 diff 函数,它使用 view
来避免复制数据:
object viewDiff {
def main(args: Array[String]){
val values = 1 to 10
println("diff="+diffInt(values).toList)
}
def diffInt(seq: Seq[Int]): Seq[Int] = {
val v1 = seq.view(0,seq.size-1)
val v2 = seq.view(1,seq.size)
(v2,v1).zipped.map(_-_)
}
}
此代码失败并显示 UnsupportedOperationException
。如果我使用 slice
而不是 view
它会起作用。
谁能解释一下?
[使用 scala 2.10.5 和 2.11.6 测试]
编辑
我选择了 because it was the (first) correct explanation of the problem. However, 更详细,并提供了一个在压缩对象上使用视图的简单解决方案。
我还发布了适用于此特定案例的 。
备注
在上面的代码中,我在计算seq导数的算法上也犯了一个错误。最后一行应该是:seq.head +: (v2,v1).zipped.map( _-_ )
当您在代码中使用 seq.view
时,您正在创建 SeqView[Int, Seq[Int]]
个无法压缩的对象,因为它不支持 TraversableView.Builder.result
。但是你可以使用这样的东西:
def diffInt(seq: Seq[Int]) = {
val v1 = seq.view(0,seq.size-1)
val v2 = seq.view(1,seq.size)
(v2.toList,v1.toList).zipped.map {
case (x1: Int, y1: Int) => x1-y1
case _ => 0
}
}
与一样,压缩后无法使用视图。在我看来像是一个错误...
但这只有在第一个压缩序列是一个视图时才会发生。由于压缩在其任何序列完成时停止,因此可以将整个输入序列用作第一个压缩项目并反转 - 操作:
def diffInt2(seq: Seq[Int]): Seq[Int] = {
val v1 = seq//.view(0,seq.size-1)
val v2 = seq.view(1,seq.size)
seq.head +: (v1,v2).zipped.map( (a,b) => b-a ) // inverse v1 and v2 order
}
这看起来确实很奇怪,zipped
似乎是罪魁祸首。你可以做的是,作为一个最小的变化,使用 zip
:
def diffInt(seq: Seq[Int]): Seq[Int] = {
val v1 = seq.view(0,seq.size-1)
val v2 = seq.view(1,seq.size)
v2.zip(v1).map { case (x1, x2) => x1 - x2 }
}
啊,命令式编程的那些美好时光:
val seq = 1 to 10
val i1 = seq.iterator
val i2 = seq.iterator.drop(1)
val i = scala.collection.mutable.ArrayBuffer.empty[Int]
while (i1.hasNext && i2.hasNext) i += i2.next - i1.next
println(i)
我想说它非常高效(没有复制和过度分配),而且可读性很好。
通常,您在 map
ping 视图时不会构建视图,因为您想推迟构建结果集合,直到 force
视图。
由于 Tuple2Zipped
不是视图,因此它会尝试在地图上构建与其第一个元组集合(即视图)类型相同的结果。
SeqView
的CanBuildFrom
产生拒绝被强制的NoBuilder
。
由于使用Tuple2Zipped
的目的是为了避免中间集合,你也想避免过早地强制,所以在映射之前先看一下:
scala> Seq(1,2,3).view(1,3)
res0: scala.collection.SeqView[Int,Seq[Int]] = SeqViewS(...)
scala> Seq(1,2,3).view(0,2)
res1: scala.collection.SeqView[Int,Seq[Int]] = SeqViewS(...)
scala> (res0, res1).zipped
res2: scala.runtime.Tuple2Zipped[Int,scala.collection.SeqView[Int,Seq[Int]],Int,scala.collection.SeqView[Int,Seq[Int]]] = (SeqViewS(...), SeqViewS(...)).zipped
scala> res2.view map { case (i: Int, j: Int) => i - j }
res3: scala.collection.TraversableView[Int,Traversable[_]] = TraversableViewM(...)
scala> .force
res4: Traversable[Int] = List(1, 1)
看一下机制:
import collection.generic.CanBuildFrom
import collection.SeqView
import collection.mutable.ListBuffer
import language._
object Test extends App {
implicit val cbf = new CanBuildFrom[SeqView[Int, Seq[Int]], Int, Seq[Int]] {
def apply(): scala.collection.mutable.Builder[Int,Seq[Int]] = ListBuffer.empty[Int]
def apply(from: scala.collection.SeqView[Int,Seq[Int]]): scala.collection.mutable.Builder[Int,Seq[Int]] = apply()
}
//val res = (6 to 10 view, 1 to 5 view).zipped.map[Int, List[Int]](_ - _)
val res = (6 to 10 view, 1 to 5 view).zipped.map(_ - _)
Console println res
}
我在 Seq[Int]
上定义了以下 diff 函数,它使用 view
来避免复制数据:
object viewDiff {
def main(args: Array[String]){
val values = 1 to 10
println("diff="+diffInt(values).toList)
}
def diffInt(seq: Seq[Int]): Seq[Int] = {
val v1 = seq.view(0,seq.size-1)
val v2 = seq.view(1,seq.size)
(v2,v1).zipped.map(_-_)
}
}
此代码失败并显示 UnsupportedOperationException
。如果我使用 slice
而不是 view
它会起作用。
谁能解释一下?
[使用 scala 2.10.5 和 2.11.6 测试]
编辑
我选择了
我还发布了适用于此特定案例的
备注
在上面的代码中,我在计算seq导数的算法上也犯了一个错误。最后一行应该是:seq.head +: (v2,v1).zipped.map( _-_ )
当您在代码中使用 seq.view
时,您正在创建 SeqView[Int, Seq[Int]]
个无法压缩的对象,因为它不支持 TraversableView.Builder.result
。但是你可以使用这样的东西:
def diffInt(seq: Seq[Int]) = {
val v1 = seq.view(0,seq.size-1)
val v2 = seq.view(1,seq.size)
(v2.toList,v1.toList).zipped.map {
case (x1: Int, y1: Int) => x1-y1
case _ => 0
}
}
与
但这只有在第一个压缩序列是一个视图时才会发生。由于压缩在其任何序列完成时停止,因此可以将整个输入序列用作第一个压缩项目并反转 - 操作:
def diffInt2(seq: Seq[Int]): Seq[Int] = {
val v1 = seq//.view(0,seq.size-1)
val v2 = seq.view(1,seq.size)
seq.head +: (v1,v2).zipped.map( (a,b) => b-a ) // inverse v1 and v2 order
}
这看起来确实很奇怪,zipped
似乎是罪魁祸首。你可以做的是,作为一个最小的变化,使用 zip
:
def diffInt(seq: Seq[Int]): Seq[Int] = {
val v1 = seq.view(0,seq.size-1)
val v2 = seq.view(1,seq.size)
v2.zip(v1).map { case (x1, x2) => x1 - x2 }
}
啊,命令式编程的那些美好时光:
val seq = 1 to 10
val i1 = seq.iterator
val i2 = seq.iterator.drop(1)
val i = scala.collection.mutable.ArrayBuffer.empty[Int]
while (i1.hasNext && i2.hasNext) i += i2.next - i1.next
println(i)
我想说它非常高效(没有复制和过度分配),而且可读性很好。
通常,您在 map
ping 视图时不会构建视图,因为您想推迟构建结果集合,直到 force
视图。
由于 Tuple2Zipped
不是视图,因此它会尝试在地图上构建与其第一个元组集合(即视图)类型相同的结果。
SeqView
的CanBuildFrom
产生拒绝被强制的NoBuilder
。
由于使用Tuple2Zipped
的目的是为了避免中间集合,你也想避免过早地强制,所以在映射之前先看一下:
scala> Seq(1,2,3).view(1,3)
res0: scala.collection.SeqView[Int,Seq[Int]] = SeqViewS(...)
scala> Seq(1,2,3).view(0,2)
res1: scala.collection.SeqView[Int,Seq[Int]] = SeqViewS(...)
scala> (res0, res1).zipped
res2: scala.runtime.Tuple2Zipped[Int,scala.collection.SeqView[Int,Seq[Int]],Int,scala.collection.SeqView[Int,Seq[Int]]] = (SeqViewS(...), SeqViewS(...)).zipped
scala> res2.view map { case (i: Int, j: Int) => i - j }
res3: scala.collection.TraversableView[Int,Traversable[_]] = TraversableViewM(...)
scala> .force
res4: Traversable[Int] = List(1, 1)
看一下机制:
import collection.generic.CanBuildFrom
import collection.SeqView
import collection.mutable.ListBuffer
import language._
object Test extends App {
implicit val cbf = new CanBuildFrom[SeqView[Int, Seq[Int]], Int, Seq[Int]] {
def apply(): scala.collection.mutable.Builder[Int,Seq[Int]] = ListBuffer.empty[Int]
def apply(from: scala.collection.SeqView[Int,Seq[Int]]): scala.collection.mutable.Builder[Int,Seq[Int]] = apply()
}
//val res = (6 to 10 view, 1 to 5 view).zipped.map[Int, List[Int]](_ - _)
val res = (6 to 10 view, 1 to 5 view).zipped.map(_ - _)
Console println res
}