假设我有一个迭代器:
val it = List("a","b","c").iterator
我想要它的一个副本; 我的代码是:
val it2 = it.toList.iterator
这是正确的,但似乎不太好。有没有其他API可以做到这一点?
你要查找的方法是 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
it1
和 it2
可以独立使用,但是调用 it.next
会同时推进这两个副本!而且,这些副本从 it
的当前元素开始,而不是列表的开头。不幸的是,duplicate
的文档说明特别不好。 - Raphaelit
现在指的是it1
所指的相同内容。 - Rex Kerr警告:从Scala 2.9.0开始,使用这种方法后,原始迭代器至少会变为空。您可以val ls = it.toList; val it1 = ls.iterator; val it2 = ls.iterator
来获得两个副本。或者使用duplicate(对于非列表也适用)。
Rex的回答是标准的,但实际上您的原始解决方案对于scala.collection.immutable.List而言效率最高。
可以使用该机制轻松复制列表迭代器而几乎不会增加额外开销。可以通过快速查看scala.collection.immutable.LinearSeq中iterator()的实现方式进行确认,特别是toList方法的定义,它只是返回支持Seq的_.toList,如果它是一个List(正如您的情况),则是identity。
在调查您的问题之前,我不知道列表迭代器具有这种属性,我非常感谢这些信息......这意味着许多"列表削尖"算法可以使用迭代器作为削尖器,在Scala不可变列表上高效实现。
val
切换到def
会使每次引用符号(在上面的示例中命名为it
)时都获得一个新的迭代器。在许多情况下,这种方式可能会感觉更简单。 - matanster