Scala类型是Iterable并且有长度?

时间:2011-07-05 09:50:46

标签: scala types size iterable

编写Scala代码时,我经常遇到这样的情况:我有“处理器”函数,它们在元素集合上迭代运行,并且还需要知道集合的长度。

另一方面,我有“提供者”功能,可以生成集合,因此已经知道了长度。生成的集合可能是List[T]Array[T]Set[T]等,但即使在List[T]的情况下,我的生成器也知道大小(即使{{1} }}类型不存储它)。

所以我自然会将“处理器”函数声明为采用似乎适合所有集合类型List的最通用类型作为参数。然而,他们在内部需要通过迭代收集遍历以O(N)的代价找出大小,这是不希望的。

所以我天真的解决方案是创建一个像Iterable[T]这样的新类型,并让提供者和处理器函数创建并采用这种类型。 IterableWithSize[T]Seq[T]似乎都不符合要求。但这似乎是一个相对常见的用例,所以我怀疑有一种更惯用的方法来做到这一点。那会是什么?

4 个答案:

答案 0 :(得分:2)

在Scala集合中,性能敏感的方法(如size)不是从特征继承而是在底部类型中重写。例如,请参阅immutable.HashSet

的实现

https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_0_1/src//library/scala/collection/immutable/HashSet.scala

所以你不需要关心它。只需定义一个高级别的共同特征,例如TraversableIterable,您就完成了。

答案 1 :(得分:2)

实际上,没有惯用的方法。 Scala集合实际上是要以其他规定的方式遍历或使用(例如Set.containsMap.get)。检查尺寸不是它们的一部分,其中一些甚至不是有限的。

现在,IndexedSeq是一个相对安全的赌注 - 它保证了O(logn)索引访问,这只有在你有O(logn)大小时才有可能。此外,由于类似原因,SetMap也相当安全。但是如果你正在寻找能够以size速度保证的特性,那就没有。{/ p>

答案 2 :(得分:1)

Traversable怎么样?您提及的所有馆藏都会从中继承(Array间接通过WrappedArray),并提供sizetoIterable(或toIterator)进行遍历。

答案 3 :(得分:1)

我认为没有一种惯用的方法可以做到这一点。但这里有两种选择:

(1)扩展Scala的List / Set / Array集合并覆盖size方法。这并不像第一眼看上去那么困难。

(2)将List / Set / Array集合与大小一起包装,并定义一个隐式的解包器,如:

class IterableWithSizeWrapper[E](private val c: Iterable[E], val size: Int)
object IterableWithSizeWrapper {
  implicit def unwrap[E](iws: IterableWithSizeWrapper[E]): Iterable[E] = iws.c
}

object ListWithSizeTest {

  def process[E](iws: IterableWithSizeWrapper[E]) {
        // iws.size uses your cached size value
        // iws.take(i) forces the unwrap to the original collect
        // so iws.take(i).size takes the calculated size
    for (i <- 0 to iws.size) assert(iws.take(i).size == i)
  }

  def main(args: Array[String]) {
    process(new IterableWithSizeWrapper(List(1,2,3), 3))
    process(new IterableWithSizeWrapper(Set(1,2,3), 3))
    process(new IterableWithSizeWrapper(Array(1,2,3), 3))
  }
}