【问题标题】:Writing a generic 'fill' method编写通用的“填充”方法
【发布时间】:2011-09-05 18:12:13
【问题描述】:

我正在尝试编写一个通用的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)

这适用于除数组之外的所有可遍历集合。如何使此代码与数组一起使用?

【问题讨论】:

  • 我也想出了this 替代版本,它适用于数组,但我不喜欢它有两个原因:1. 它需要我提供比我想要的更多的类型注释。 2. 它让我自己编写整个实现,而不是重用集合中的现有方法。

标签: scala collections scala-collections


【解决方案1】:

如果你不介意创建一个额外的对象,那么

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)

【讨论】:

  • 我想我知道如何绕过反对意见 (2)。在下面检查我的答案。 (虽然我觉得可能有更好的方法。)
【解决方案2】:

可以稍微改变一下 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]

因为运算符符号只允许用于括号,所以我们不能省略括号。

【讨论】:

    【解决方案3】:

    我在这里使用Builder++= 方法改进了Rex 的解决方案。使用任何集合,对其执行您想要执行的任何操作,然后最后将其添加到构建器对象中,然后获取其结果。

    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)
    

    【讨论】:

    • 如果您不介意花费两倍的时间(因为您构建相同的集合两次),我想这会“更好”。
    • @Rex:我还能如何重用 stdlib 中的函数,而不是推出基于构建器的命令式实现?
    • 也许你不能,但是很多辅助函数很容易重新实现。
    猜你喜欢
    • 1970-01-01
    • 2023-02-10
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-11
    • 2013-07-19
    相关资源
    最近更新 更多