Suppose I have a List[Int], and I want to call toString on each element, and get back the result as a Vector[String].
What are the various ways to do this in Scala? Is there a solution with a minimal amount of explicit typing? — i.e., I want to specify that I want a Vector rather than a List, but I'd like the String argument to be inferred from the filter function.
Or should I explicitly pass a CanBuildFrom instance? Where do I get these from — for Seqs, Sets and Maps?
Use breakOut as the CanBuildFrom and let the typer know what you want your result type to be (unfortunately you need to specify String here)
scala> import collection.breakOut
import collection.breakOut
scala> List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)
scala> res0.map(_.toString)(breakOut) : Vector[String]
res2: Vector[String] = Vector(1, 2, 3)
Scala 2.10.0 introduced an easy way to convert a collection to another collection:
scala> List(1, 2, 3).map(_.toString).to[Vector]
res0: Vector[String] = Vector(1, 2, 3)
Alternatively ask for an IndexedSeq explicitly:
scala> res0.map(_.toString).toIndexedSeq
res4: scala.collection.immutable.IndexedSeq[String] = Vector(1, 2, 3)
If you want to do this without creating the intermediate List, then:
scala> res0.view.map(_.toString).toIndexedSeq
res5: scala.collection.immutable.IndexedSeq[String] = Vector(1, 2, 3)
You could do it (awkwardly, but more generally) using natural transformations
scala> trait Trans[F[_], G[_]] {
| def f2g[A](f : F[A]) : G[A]
| }
defined trait Trans
Now provide a typeclass instance from the List ~> Vector transformation:
scala> implicit val List2Vector = new Trans[List, collection.immutable.Vector] {
| def f2g[A](l : List[A]) : Vector[A] = l.map(identity[A])(collection.breakOut)
| }
List2Vector: java.lang.Object with Trans[List,scala.collection.immutable.Vector] = $anon$1@56329755
Define a wrapper and an implicit conversion:
scala> class Clever[M[_], A](ma : M[A]) { def to[N[_]](implicit t : Trans[M, N]) : N[A] = t.f2g(ma) }
defined class Clever
scala> implicit def ma2clever[M[_], A](ma : M[A]) = new Clever[M, A](ma)
ma2clever: [M[_],A](ma: M[A])Clever[M,A]
Then:
scala> List(1, 2, 3).map(_.toString).to[Vector]
res4: Vector[java.lang.String] = Vector(1, 2, 3)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With