Enrich-My-Library for all traverses

I tried to figure out how to write a functional swap function that works on any Traversable[_] , given the collection and swap indices. I came up with the following:

 def swap[A, CC <% Traversable[A]](xs: CC, i: Int, j: Int): Traversable[A] = { xs.slice(0, i) ++ xs.slice(j, j+1) ++ xs.slice(i+1, j) ++ xs.slice(i, i+1) ++ xs.slice(j+1, xs.size) } swap(List(1,2,3,4,5), 0, 4) // => List(5,2,3,4,1) 

I would like to know how to do this in an implicit Traversable extension, letting me call it List(1,2,3,4,5).swap(0, 4) . The closest I could get is this:

 import language.implicitConversions class RichTraversable[A, B <% Traversable[A]](xs: B) { def swap(i: Int, j: Int): Traversable[A] = { xs.slice(0, i) ++ xs.slice(j, j+1) ++ xs.slice(i+1, j) ++ xs.slice(i, i+1) ++ xs.slice(j+1, xs.size) } } implicit def richTraversable[A, B <% Traversable[A]](ys: B)(implicit b: Traversable[A]) = new RichTraversable[A, B](ys) 

Unfortunately, this is not entirely true. Calling List(1,2,3,4,5).swap(0, 4) results in the following error:

error: implicit view from the list [Int] => Traversable [A] is not available

I feel that I am missing something, or that complicates the problem too much. Does anyone know how this should be structured?


Note. It is purely academic and is not used in any way in the production environment. I am trying to get a better system descriptor and restrictions like Scala.

+6
source share
1 answer

If you are using Scala 2.10:

 import scala.collection.generic.CanBuildFrom import scala.collection.TraversableLike implicit class TraversableWithSwap[A, Repr <: Traversable[A]](val xs: TraversableLike[A, Repr]) extends AnyVal { def swap[That](i: Int, j: Int)(implicit bf: CanBuildFrom[Repr, A, That]): That = { val builder = bf(xs.asInstanceOf[Repr]) builder.sizeHint(xs) builder ++= xs.take(i) builder ++= xs.slice(j, j + 1) builder ++= xs.slice(i + 1, j) builder ++= xs.slice(i, i + 1) builder ++= xs.drop(j + 1) builder.result } } 

(The AnyVal object turns it into a class of values, which means that the compiler will rewrite it as a static function to avoid the actual execution of the transfer at run time.)

If you are using an earlier version, release extends AnyVal and use the implicit conversion function instead of the implicit class :

 implicit def toTraversableWithSwap[A, Repr <: Traversable[A]](xs: TraversableLike[A, Repr]) = new TraversableWithSwap(xs) 

And using it:

 scala> Vector(1,2,3,4,5,6,7,8,9).swap(2,5) res0: scala.collection.immutable.Vector[Int] = Vector(1, 2, 6, 4, 5, 3, 7, 8, 9) 

Please note that in fact it makes no sense to define this function for all Traversable , since some traverses (for example, Set , Map , etc.) are disordered, so exchanging two elements does not make sense. You will probably want to define it for all Seq or something else.

Also: Can we also agree to call it already "improving my library"?

+4
source

All Articles