【问题标题】:How to clone an iterator?如何克隆迭代器?
【发布时间】:2011-07-10 08:35:59
【问题描述】:

假设我有一个迭代器:

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

我想要它的副本;我的代码是:

val it2 = it.toList.iterator

说得对,但好像不太好。有没有其他 API 可以做到这一点?

【问题讨论】:

  • 为什么?一旦你克隆了它,原来的迭代器将被消耗掉并且无用,从而首先打败了克隆的全部意义......
  • @Kevin,不一定是这样,对吧?抽象地说,似乎有可能有一个操作为我提供一个迭代器,该迭代器将返回与源迭代器相同的序列 - 当然,状态问题可能使所有迭代器都不可能。它似乎本质上不需要消耗源代码。
  • val 切换到def 会在每次引用符号时给你一个新的迭代器(在上面的例子中命名为it)。在许多情况下,这种方式可能感觉更简单。

标签: scala iterator


【解决方案1】:

警告:至少从 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 迭代器的这个属性,我非常感谢您提供的信息......除此之外,这意味着许多“list pebbling”算法可以通过 Scala 不可变有效地实现使用迭代器作为鹅卵石的列表。

【讨论】:

【解决方案2】:

您要查找的方法是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

【讨论】:

  • 警告:这使用可变的Queue 来缓存迭代器之间的差异,这可能会导致意外的内存问题。此外,nexthasNext 是新迭代器的 synchronized,这使得它们比普通迭代器慢得多。
  • 另一个警告:虽然it1it2 可以独立使用,但调用it.next 会转发两个副本!此外,重复项从it 的当前元素开始,而不是列表的开头。可悲的是,duplicate 的记录尤其糟糕。
  • 已发出警告。它们很重要,但如果您仔细考虑您的要求,它们也是“不言而喻的”:当然,如果您有一个迭代器并且想要两个不同步的迭代器,那么您将需要某种存储,你只能从你所在的地方开始,而不是回到丢失的开始,如果你不只是要复制 everything 那么你需要同步以便找出两个迭代器留下的东西以及准备抓取的东西。
  • @Rex Kerr,只是一个问题,我可以将其中一个重复迭代器重新分配给原始迭代器并从那时起继续使用原始迭代器吗? val(it1,it2) = it.duplicate it = it1 println(it.length) println(it2.mkString)
  • @HaseebJaved - 为什么不呢?你只是说it 现在指的是与it1 相同的东西。
猜你喜欢
  • 2018-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-19
  • 1970-01-01
  • 2011-10-21
  • 2020-08-24
  • 2015-11-23
相关资源
最近更新 更多