如何克隆迭代器?

Fre*_*ind 17 iterator scala

假设我有一个迭代器:

val it = List("a","b","c").iterator
Run Code Online (Sandbox Code Playgroud)

我想要一份副本; 我的代码是:

val it2 = it.toList.iterator
Run Code Online (Sandbox Code Playgroud)

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

Rex*_*err 19

你正在寻找的方法是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
Run Code Online (Sandbox Code Playgroud)

  • 警告:这使用可变的`Queue`来缓存迭代器之间的差异,这可能会导致意外的内存问题.另外,对于新的迭代器,`next`和`hasNext`是`synchronized`,这使得它们比普通的迭代器慢得多. (3认同)
  • 另一个警告:虽然`it1`和`it2`可以独立使用,但调用`it.next`可以转发两个副本!此外,重复项从`it`的当前元素开始,而不是列表的开头.遗憾的是,"复制"特别严重. (3认同)
  • 警告已授予.它们很重要,但如果你仔细考虑你所要求的东西,它们也是"不言而喻"的:当然,如果你有一个迭代器并且你想要两个不同步的东西,你会去需要某种存储,你只能从你所在的地方开始,而不是回到一个迷失的开端,如果你不只是要复制_everything_那么你需要同步才能找出遗留的东西通过迭代器和准备抓取的东西. (2认同)
  • @HaseebJaved - 为什么不呢?你只是说`it`现在指的是'it1`所做的相同的东西. (2认同)

Mil*_*bin 9

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

Rex的答案在于本书,但实际上你的原始解决方案对于scala.collection.immutable.List来说是最有效的.

列表迭代器可以使用该机制进行复制,基本上没有开销.这可以通过快速查看scala.collection.immutable.LinearSeq中的iterator()的实现来确认.toList方法的定义,它简单地返回后备Seq的_.toList,如果它是List(就像你的情况那样)是标识.

在调查你的问题之前,我并不知道List迭代器的这个属性,我非常感谢这些信息......除此之外,它意味着许多"列表修改"算法可以使用迭代器在Scala不可变列表上高效实现像鹅卵石一样.