我在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测试]
我选择了Carlos's answer,因为它是(第一个)问题的正确解释。但是,som-snytt's answer更详细,并提供了一个使用压缩对象视图的简单解决方案。
我还发布了适用于此特定情况的very simple solution 。
在上面的代码中,我也在计算seq导数的算法上犯了一个错误。最后一行应为:seq.head +: (v2,v1).zipped.map( _-_ )
答案 0 :(得分:2)
在代码中使用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
}
}
答案 1 :(得分:2)
这看起来确实很奇怪,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 }
}
答案 2 :(得分:2)
通常,在map
ping它们时,您不会构建视图,因为您希望推迟构建结果集合,直到force
视图为止。
由于Tuple2Zipped
不是视图,因此在地图上它会尝试构建与第一个tupled集合相同类型的结果,这是一个视图。
SeqView
的{{1}}会产生拒绝强制的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)
答案 3 :(得分:1)
啊,那些命令式编程的好时光:
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)
我说它有效率(没有复制和过多的分配),并且非常易读。
答案 4 :(得分:0)
作为Carlos Vilchez wrote,压缩无法使用视图。对我来说看起来像个错误......
但只有当第一个压缩的seq是视图时才会发生这种情况。由于zipped在任何seq完成时停止,因此可以使用整个输入seq作为第一个压缩项并反向 - 操作:
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
}