在Scala中的一个for循环中有效地迭代一个Set,然后是另一个

时间:2013-06-29 08:41:56

标签: scala loops scala-collections

我希望使用单个循环迭代一个Set的所有元素,然后迭代另一个Set的所有元素。 (我不关心重复,因为我碰巧知道这两个Set是不相交的。)

我想在单个循环中执行此操作的原因是因为我有一些额外的代码来测量进度,这需要它在一个循环中。

这一般不起作用,因为它可能会任意混合两个Set

for(x <- firstSet ++ secondSet) {
   ...
}

这可行,但在内存中构建了3个中间Seq,因此在时间和空间使用方面效率太低:

for(x <- firstSet.toSeq ++ secondSet.toSeq) {
   ...
}

2 个答案:

答案 0 :(得分:11)

for(x <- firstSet.toIterator ++ secondSet.toIterator) {
   ...
}

这不构建任何中间数据结构,所以我认为这是最有效的方式。

答案 1 :(得分:5)

如果你只想要一次遍历,并且想要获得最佳性能,那么这是最好的方法,即使它很难看:

val s1 = Set(1,2,3)
val s2 = Set(4,5,6)
val block : Int => Unit = x => { println(x) }
s1.foreach(block)
s2.foreach(block)

由于这非常难看,你可以为它定义一个类:

def traverse[T](a:Traversable[T], b:Traversable[T]) : Traversable[T] = 
  new Traversable[T] { 
    def foreach[U](f:T=>U) { a.foreach(f); b.foreach(f) } 
  }

然后像这样使用它:

for(x<-traverse(s1, s2)) println(x)

然而,除非这对性能至关重要,否则Robin Green发布的解决方案会更好。开销是创建两个迭代器并连接它们。如果你有更深层次的嵌套数据结构,那么连接迭代器可能会非常昂贵。例如,通过连接子树的迭代器定义的树迭代器将非常缓慢,而在每个子树上调用foreach的树遍历将接近最优。