【问题标题】:Constructing BitSets in Scala from a predicate?在 Scala 中从谓词构造位集?
【发布时间】:2013-03-03 12:49:26
【问题描述】:

假设我想构造一个包含从 0 到 n 的所有整数满足某个谓词 f: Int => Boolean 的 BitSet。

我可以写类似的东西

BitSet((0 until n):_*).filter(f)

这当然有效。但是感觉效率很低!我计划在一个非常紧凑的循环中执行此操作,并希望获得更有效方法的建议。

【问题讨论】:

    标签: scala bitset


    【解决方案1】:

    如果性能确实是您最关心的问题,最好的选择可能是使用mutable.BitSet 和while 循环,然后在结果上调用toImmutable

    val bitSet = {
      val tmp = new scala.collection.mutable.BitSet(n)
      var i = 0;
      while (i < n) {
        if (f(i)) {
          tmp += i
        }
        i = i + 1
      }
      tmp.toImmutable
    }
    

    【讨论】:

      【解决方案2】:

      我认为最有效的“功能”方式是使用foldLeft

      (1 to 5).foldLeft(BitSet())((s,i) => if (f(i)) s + i else s)
      

      它不会创建中间集合,而是在过滤时从头开始构建集合。

      我首先想到的是使用breakOut,但是对于filter却不行:

      scala> val set: BitSet = (0 until 10).filter(f)(collection.breakOut)
      <console>:11: error: polymorphic expression cannot be instantiated to expected type;
       found   : [From, T, To]scala.collection.generic.CanBuildFrom[From,T,To]
       required: Int
             val set: BitSet = (0 until 10).filter(f)(collection.breakOut)
                                                                 ^
      
      scala> val set: BitSet = (0 until 10).map(_+1)(collection.breakOut)
      set: scala.collection.immutable.BitSet = BitSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
      

      breakOut 也不会创建中间集合,但是因为filter 没有第二个参数列表,所以它不能工作。

      【讨论】:

        【解决方案3】:

        这是我目前能想到的最好的方法

        BitSet((0 until n).view.filter(f):_*)
        

        视图部分使filter 方法变得懒惰。这确保当BitSet 从给定序列创建时,它会即时过滤。您最初的建议在创建第一个 BitSet 后创建一个新的。

        【讨论】:

        • 你说的不是真的,filter 创建了一个中间集合,即使使用view。事实上view在这里完全没用。 : _* 表示直接传递参数,而不是将其包装在一个序列中。
        • 重复的参数不是“直接”传递的(如推送到参数堆栈中),而是放置在一种IndexedSeq 中,并作为单个参数传递给方法。换句话说,它们肯定包裹了。
        • @Randall Schulz:是的,但 schaef 是对的。 RangeTraversableLike 继承其 filter 实现,在此处定义:github.com/scala/scala/blob/v2.10.1/src/library/scala/…。如您所见,它遍历原始集合的每个元素(它只是foreach),因此即使通过view 使集合变得懒惰,filter 仍将强制评估原始集合的每个元素.因此,在这种情况下,使用 view 实际上可以通过引入不必要的额外间接来使事情变得更糟。
        猜你喜欢
        • 2021-04-07
        • 2010-10-11
        • 1970-01-01
        • 1970-01-01
        • 2015-02-23
        • 1970-01-01
        • 2012-09-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多