加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – Traversable => Java Iterator

发布时间:2020-12-16 08:54:07 所属栏目:安全 来源:网络整理
导读:我有一个Traversable,我想把它变成一个 Java Iterator.我的问题是我希望一切都懒洋洋地完成.如果我在遍历上执行.toIterator,它会急切地产生结果,将其复制到List中,并在List上返回一个迭代器. 我确定我在这里错过了一些简单的东西…… 这是一个小测试用例,显
我有一个Traversable,我想把它变成一个 Java Iterator.我的问题是我希望一切都懒洋洋地完成.如果我在遍历上执行.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

解决方法

你不能懒得从一个遍历得到一个迭代器的原因是你本质上不能. Traversable定义了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
  }
}

如果您碰巧有效的索引切片,这将是可以的.如果不是,则每个“next”将在迭代器的长度上花费时间线性,对于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风格的演员(尽管任何旧演员或Akka演员或Scalaz演员或者Lift演员或者(等)将工作)

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一般都不是懒惰的,没有好办法让它变得懒惰而不会极大地影响性能.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读