Inability to parse

I define the following diff function on Seq[Int] , which uses view to avoid copying data:

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

This code does not work with UnsupportedOperationException . If I use slice instead of view , it works.

Can anyone explain this?

[verified using scala 2.10.5 and 2.11.6]

Edit

I chose Carlos's answer because it was the (first) correct explanation of the problem. However, som-snytt answer is more verbose and provides a simple solution using a view on an archived object.

I also posted a very simple solution that works for this particular case.

Note

In the above code, I also made a mistake in the algorithm for computing the derivative of seq. The last line should be: seq.head +: (v2,v1).zipped.map( _-_ )

+5
source share
5 answers

When you use seq.view in your code, you create SeqView[Int, Seq[Int]] objects that cannot be fixed because they cannot support TraversableView.Builder.result . But you can use something like this:

 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 } } 
+2
source

It looks weird, and zipped seems to be the culprit. Instead, as a minimal change, you can use 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
source

Usually you do not create views when map ping them, since you want to defer the creation of a collection of results until you see force .

Since Tuple2Zipped not a view, it tries to build a result on it that is the same type as its first set, which is a view.

SeqView CanBuildFrom gives NoBuilder , which refuses forcibly.

Since the point of using Tuple2Zipped is to avoid intermediate collections, you should also avoid premature forcing, so you need to make a representation before displaying:

 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) 

Here we consider the mechanism:

 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 } 
+2
source

Ah, these good old days of imperative programming:

 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) 

I would say that it is effective, like it (without copying and excessive distributions), and quite easy to read.

+1
source

As Carlos Vilchez wrote , zipped cannot work with a view. Looks like a mistake to me ...

But this only happens if the first zipped seq is a view. When zipped stops when any of its seq is finished, you can use all seq input as the first archived item and invert the operation:

 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) => ba ) // inverse v1 and v2 order } 
0
source

Source: https://habr.com/ru/post/1244300/


All Articles