2011-03-07 107 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