Writing a generic 'fill' method
I am trying to write a generic fill
method, and following is wha开发者_运维百科t I have come up with so far:
scala> import collection.generic.{GenericTraversableTemplate => GTT}
import collection.generic.{GenericTraversableTemplate=>GTT}
scala> import collection.generic.{TraversableFactory => TF}
import collection.generic.{TraversableFactory=>TF}
scala> def fill[A, CC[X] <: Traversable[X] with GTT[X, CC]]
| (n: Int)(elem: => A)(tf: TF[CC]) = tf.fill(n)(elem)
fill: [A, CC[X] <: Traversable[X] with scala.collection.generic.GenericTraversab
leTemplate[X,CC]](n: Int)(elem: => A)(tf: scala.collection.generic.TraversableFa
ctory[CC])CC[A]
scala> fill(3)('d')(List)
res42: List[Char] = List(d, d, d)
This works with all traversable collections except arrays. How do I make this code work with arrays?
If you don't mind creating an extra object, there's
def fill[CC[_]](n: Int) = new {
def apply[A](elem: => A)(implicit cbf: CanBuildFrom[Nothing, A, CC[A]]) = {
val b = cbf()
1 to n foreach { _ => b += elem }
b.result
}
}
It doesn't get around objection (2), but the usage is nice:
scala> fill[List](3)("wish")
res0: List[java.lang.String] = List(wish, wish, wish)
scala> fill[Array](3)("wish")
res1: Array[java.lang.String] = Array(wish, wish, wish)
It is possible to change the syntax of Rex' solution a little bit:
class Filler(n: Int) {
def timesOf[A](elem: => A) = new Builder[A](elem)
class Builder[A](elem: => A) {
import scala.collection.generic.CanBuildFrom
def fillIn[CC[_]](implicit cbf: CanBuildFrom[Nothing, A, CC[A]]) = {
val b = cbf()
for (_ <- 1 to n) b += elem
b.result
}
}
}
implicit def int2Filler(n: Int) = new Filler(n)
// use as
(3 timesOf true).fillIn[List]
Because operator notation is only allowed for parentheses, we can't omit the brackets.
I have bettered Rex's solution here by using Builder
's ++=
method. Use any collection, perform on it whatever operations you want to perform, and then finally add it to the builder object and then take its result.
scala> def fill[CC[_]](n: Int) = new {
| def apply[A](elem: => A)
| (implicit cbf: CanBuildFrom[Nothing, A, CC[A]]) = {
| val b = cbf.apply
| b ++= Vector.fill(n)(elem)
| b.result
| }
| }
fill: [CC[_]](n: Int)java.lang.Object{def apply[A](elem: => A)(implicit cbf: sca
la.collection.generic.CanBuildFrom[Nothing,A,CC[A]]): CC[A]}
scala> fill[List](3)("hullo")
res8: List[java.lang.String] = List(hullo, hullo, hullo)
精彩评论