2011-03-07 134 views
15

假设我有一个迭代器:如何克隆迭代器?

val it = List("a","b","c").iterator 

我想它的一个副本;我的代码是:

val it2 = it.toList.iterator 

这是正确的,但似乎并不好。有没有其他API可以做到这一点?

+0

为什么?一旦你克隆了它,原来的迭代器将被消耗掉并且无用,从而首先击败克隆的整个点... – 2011-03-07 13:32:59

+2

@Kevin,这不一定是这种情况,当然?抽象地说,似乎可能有一个操作给我一个迭代器,它将返回与源迭代器相同的序列 - 当然,状态问题可能使所有迭代器都不可能。它似乎并不需要消耗源代码。 – 2011-03-07 13:44:23

+0

每次你引用符号(在上面的例子中命名为'it'),从'val'切换到'def'会给你一个新的迭代器。在很多情况下,这种方式可能会更简单。 – matanster 2016-01-22 17:44:44

回答

9

警告:从Scala 2.9.0开始,至少这会使原始迭代器为空。你可以val ls = it.toList; val it1 = ls.iterator; val it2 = ls.iterator得到两份。或者使用重复(也适用于非列表)。

雷克斯的答案是由书,但实际上你的原始解决方案是迄今为止最有效的scala.collection.immutable.List's。

列表迭代器可以使用该机制进行复制,而基本没有开销。这可以通过快速查看scala.collection.immutable.LinearSeq中的iterator()的实现来确认,尤其是, toList方法的定义,它只是返回支持Seq的_.toList,如果它是一个List(就你的情况而言)是身份。

在调查您的问题之前,我并没有意识到List迭代器的这个属性,我非常感谢这些信息......除此之外,这意味着许多“列表串联”算法可以在Scala上有效地实现不可变的使用迭代器作为小卵石的列表。

+0

我希望我可以收到最喜欢的评论以及问题,因为你提出了一个很好的用例/点。 – 2011-03-08 02:03:20

+0

相关文章:http:// stackoverflow。COM /问题/ 16380592/SPEC2-休息,我的测试数据,由于到的路 - 这 - 作品 - 用迭代器 – ses 2013-05-05 02:21:12

17

您正在查找的方法是duplicate

scala> val it = List("a","b","c").iterator 
it: Iterator[java.lang.String] = non-empty iterator 

scala> val (it1,it2) = it.duplicate 
it1: Iterator[java.lang.String] = non-empty iterator 
it2: Iterator[java.lang.String] = non-empty iterator 

scala> it1.length 
res11: Int = 3 

scala> it2.mkString 
res12: String = abc 
+3

警告:这使用可变“队列”来缓存迭代器之间的差异,这可能会导致意外的内存问题。另外,对于新的迭代器,'next'和'hasNext'是'synchronized',这使得它们比正常的迭代器慢得多。 – 2011-03-07 19:41:28

+3

另一个警告:虽然'it1'和'it2'可以独立使用,调用'it.next'可以转发两个副本!另外,重复项从'it'的当前元素开始,而不是列表的开始。可悲的是,“重复”特别严重。 – Raphael 2011-03-07 19:57:14

+2

已授予警告。它们很重要,但如果你仔细考虑你所要求的东西,那么它也是“不言而喻的”:当然,如果你有一个迭代器,并且你想要两个不同步的东西,那么你将会需要某种类型的存储空间,你只能从你现在的位置开始,而不是回到丢失的开始位置,如果你不想复制_everything_,那么你需要同步才能找出遗留下来的东西通过迭代器和准备抓取的内容。 – 2011-03-07 22:48:23