gpt4 book ai didi

scala - 可遍历 => Java 迭代器

转载 作者:行者123 更新时间:2023-12-04 08:12:04 27 4
gpt4 key购买 nike

我有一个 Traversable,我想把它变成一个 Java 迭代器。我的问题是我希望一切都懒惰地完成。如果我在 traversable 上执行 .toIterator ,它会急切地产生结果,将其复制到一个 List 中,并在 List 上返回一个迭代器。

我确定我在这里遗漏了一些简单的东西......

这是一个小测试用例,显示了我的意思:

class Test extends Traversable[String] {
def foreach[U](f : (String) => U) {
f("1")
f("2")
f("3")
throw new RuntimeException("Not lazy!")
}
}

val a = new Test
val iter = a.toIterator

最佳答案

您不能从可遍历对象中懒惰地获取迭代器的原因是您本质上不能。可遍历定义 foreach , 和 foreach贯穿一切,不停歇。那里没有懒惰。

所以你有两种选择,都很糟糕,让它变得懒惰。

首先,您可以每次都遍历整个过程。 (我将使用 Scala Iterator,但 Java Iterator 基本相同。)

class Terrible[A](t: Traversable[A]) extends Iterator[A] {
private var i = 0
def hasNext = i < t.size // This could be O(n)!
def next: A = {
val a = t.slice(i,i+1).head // Also could be O(n)!
i += 1
a
}
}

如果您碰巧有高效的索引切片,这将没问题。如果不是,每个“下一个”将花费与迭代器长度成线性关系的时间,对于 O(n^2)时间只是为了穿越它。但这也不一定是懒惰;如果你坚持一定是你必须强制执行 O(n^2)在所有情况下,做
class Terrible[A](t: Traversable[A]) extends Iterator[A] {
private var i = 0
def hasNext: Boolean = {
var j = 0
t.foreach { a =>
j += 1
if (j>i) return true
}
false
}
def next: A = {
var j = 0
t.foreach{ a =>
j += 1
if (j>i) { i += 1; return a }
}
throw new NoSuchElementException("Terribly empty")
}
}

对于通用代码来说,这显然是一个糟糕的想法。

另一种方法是使用线程并在执行过程中阻止 foreach 的遍历。没错,您必须对每个元素访问进行线程间通信!让我们看看它是如何工作的——我将在这里使用 Java 线程,因为 Scala 正在转向 Akka 风格的 Actor (尽管任何旧 Actor 或 Akka Actor 或 Scalaz Actor 或 Lift Actor 或(等)将工作)
class Horrible[A](t: Traversable[A]) extends Iterator[A] {
private val item = new java.util.concurrent.SynchronousQueue[Option[A]]()
private class Loader extends Thread {
override def run() { t.foreach{ a => item.put(Some(a)) }; item.put(None) }
}
private val loader = new Loader
loader.start
private var got: Option[A] = null
def hasNext: Boolean = {
if (got==null) { got = item.poll; hasNext }
else got.isDefined
}
def next = {
if (got==null) got = item.poll
val ans = got.get
got = null
ans
}
}

这避免了 O(n^2)灾难,但会占用一个线程,并且逐个元素的访问速度非常慢。我在我的机器上每秒获得大约 200 万次访问,而典型的可遍历对象的访问次数超过 100M。对于通用代码来说,这显然是一个可怕的想法。

所以你有它。 Traversable 通常不是懒惰的,并且在不极大地影响性能的情况下没有什么好的方法可以使它变得懒惰。

关于scala - 可遍历 => Java 迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13192249/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com