Написание общего метода fill - PullRequest
6 голосов
/ 05 сентября 2011

Я пытаюсь написать общий fill метод, и вот что я придумал до сих пор:

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)

Работает со всеми перемещаемыми коллекциями, кроме массивов. Как мне заставить этот код работать с массивами?

Ответы [ 3 ]

10 голосов
/ 05 сентября 2011

Если вы не возражаете против создания дополнительного объекта, есть

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
  }
}

. Возражение не обходится (2), но использование неплохо:

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)
1 голос
/ 06 сентября 2011

Можно немного изменить синтаксис решения Rex:

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]

Поскольку запись оператора разрешена только для скобок, мы не можем опустить скобки.

0 голосов
/ 07 сентября 2011

Я улучшил решение Рекса, используя Builder метод ++=. Используйте любую коллекцию, выполняйте над ней любые операции, которые вы хотите выполнить, а затем, наконец, добавьте ее в объект построителя и затем получите ее результат.

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)
...