breakOut is nice, but too verbose:
List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(breakOut) : Array[(Int, Double, String)]
I don't want to specify the element type. I want something like:
List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array])
I can write a buildArray
easily, but then I'd need a buildSet, buildList, etc. So I want something generic.
Extra points ( ;-) ) if you can make it work for Map (using the same name build
, not build2 or buildMap)
This will not work for String
or Map
. Also this code requires scala.language.higherKinds
:
import collection.generic.CanBuildFrom
import collection.breakOut
class Build[To[_]]
def build[To[_]] = new Build[To]
implicit def buildToCbf[From, T, To[_]](b: Build[To])
(implicit cbf: CanBuildFrom[Nothing,T,To[T]]): CanBuildFrom[From,T,To[T]] =
collection.breakOut
List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array])
//res0: Array[(Int, Double, String)] = Array((2,0.5,1), (4,1.0,2), (6,1.5,3))
Senia's solution is great. Unfortunately as he mentioned this won't work for Map
nor String
.
Here is another alternative (based on his solution), that does:
import collection.generic.CanBuildFrom
import collection.breakOut
class Build[To]
def build[TargetSuperType] = new Build[TargetSuperType]
implicit def buildToCbf[From, T, TargetSuperType, To<:TargetSuperType](b: Build[TargetSuperType])
(implicit cbf: CanBuildFrom[Nothing,T,To]): CanBuildFrom[From,T,To] =
collection.breakOut
List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array[_]])
//res0: Array[(Int, Double, String)] = Array((2,0.5,1), (4,1.0,2), (6,1.5,3))
List(1, 2, 3).map{i => (i * 2, i.toString)}(build[Map[_,_]])
//res1: scala.collection.immutable.Map[Int,String] = Map(2 -> 1, 4 -> 2, 6 -> 3)
List('a', 'b', 'c').map(_.toUpper)(build[String])
//res2: String = ABC
This is little more verbose because now you don't just do build[Array]
, but build[Array[_]]
. In exchange you get the ability to specify any target collection you want, irrespective of the number of type arguments (such as Map
and String
).
Plus you can still be fully explicit (similarly to when using breakOut
) if you choose to:
scala> List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array[(Int, Double, String)]])
res3: Array[(Int, Double, String)] = Array((2,0.5,1), (4,1.0,2), (6,1.5,3))
All that with the same syntax (in other words, using the same name build
, as you requested)
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