【问题标题】:Scala: what is the interest in using Iterators?Scala:使用迭代器有什么好处?
【发布时间】:2016-06-14 12:24:17
【问题描述】:

在 Scala 中使用过正则表达式后,我使用过 Iterators,但我不太了解这种兴趣。
我知道它有一个状态,如果我在它上面调用 next() 方法,它每次都会输出不同的结果,但我看不到我可以用它做什么,而 Iterable 不可能做到这一点.

而且它似乎不像 Akka Streams 那样工作(例如),因为下面的例子直接打印了所有的数字(没有像我期望的那样等待一秒钟):

lazy val a = Iterator({Thread.sleep(1000); 1}, {Thread.sleep(1000); 2}, {Thread.sleep(1000); 3}) 
while(a.hasNext){ println(a.next()) } 

那么使用Iterators的目的是什么?

【问题讨论】:

  • 我不知道你在这里问什么。你期望什么作为输出,你会得到什么? “我知道它有一个状态,如果我在它上面调用 next() 方法,它不会每次都输出不同的结果”是完全错误的。迭代器通常会在每次调用next 时返回不同的结果。 “使用 Iterable 是不可能的。” - 什么是不可能的?所以你似乎对迭代器是什么感到很困惑。请编辑您的问题,看看您是否可以更清楚地说明您的要求。
  • 确实是一个了不起的问题! :)
  • @The Archetypal Paul:我想了解使用迭代器的目的。我对此一点也不困惑,但我不得不承认我的问题是(对不起我的英语)。我的意思是“它会”而不是“它不会”。我已经编辑了我的问题。
  • 当前答案在回答您的问题方面表现如何?
  • 迪玛的反应很完美,也是我所怀疑的。

标签: scala iterator


【解决方案1】:

也许,迭代器最有用的属性是它们是惰性的。 考虑这样的事情:

   (1 to 10000)
     .map { x => x * x }
     .map { _.toString }
     .find { _ == "4" }

这个 sn-p 将对 10000 个数字求平方,然后生成 10000 个字符串,然后返回第二个。 另一方面:

   (1 to 10000)
     .iterator
     .map { x => x * x }
     .map { _.toString }
     .find { _ == "4" }

...只计算两个平方,并生成两个字符串。

当您需要包装一些设计不佳的(java?)对象以便能够以函数式样式处理它们时,迭代器通常也很有用:

val rs: ResultSet = jdbcQuery.executeQuery()
new Iterator { 
   def next = rs
   def hasNext = rs.next
}.map { rs =>
   fetchData(rs)
}

流类似于迭代器——它们也是惰性的,并且对于包装也很有用:

Stream.continually(rs).takeWhile { _.next }.map(fetchData)

主要区别在于流会记住具体化的数据,因此您可以多次遍历它们。这很方便,但如果原始数据量非常大,特别是如果它被过滤到更小的大小,可能会很昂贵:

Source
  .fromFile("huge_file.txt")
  .getLines 
  .filter(_ == "")
  .toList

这仅粗略地使用(忽略缓冲、对象开销和其他实现特定的细节)内存量,在内存中保留一行所需的内存量,以及文件中存在的许多空行。

另一方面:

val reader = new FileReader("huge_file.txt")
Stream
  .continually(reader.readLine)
  .takeWhile(_ != null)
  .filter(_ == "")
  .toList

... 将在内存中以huge_file.txt全部内容结束。

最后,如果我正确理解了您示例的意图,以下是您可以如何使用迭代器:

val iterator = Seq(1,2,3).iterator.map { n => Thread.sleep(1000); n }
iterator.foreach(println)
// Or while(iterator.hasNext) { println(iterator.next) } as you had it.

【讨论】:

    【解决方案2】:

    关于什么是迭代器http://www.scala-lang.org/docu/files/collections-api/collections_43.html有一个很好的解释

    迭代器不是一个集合,而是一种访问 一个集合的元素一个一个。两个基本操作 iterator it is next 和 hasNext。调用 it.next() 将返回 迭代器的下一个元素并推进迭代器的状态。 在同一个迭代器上再次调用 next 将产生该元素 一个超出了之前返回的那个。如果没有更多元素 要返回,对 next 的调用将引发 NoSuchElementException。

    【讨论】:

      【解决方案3】:

      首先你应该明白你的例子有什么问题:

      lazy val a = Iterator({Thread.sleep(1); 1}, {Thread.sleep(1); 2}, {线程.sleep(2); 3}) while(a.hasNext){ println(a.next()) }

      如果您查看Iterator 的apply 方法,您会发现没有按名称调用,所以所有Thread.sleep 都在apply 方法调用的同时调用。同样Thread.sleep 需要以毫秒为单位的睡眠时间参数,所以如果你想在一秒钟内sleep 你的线程你应该传递Thread.sleep(1000)。 伴随对象有额外的方法可以让你做下一个:

      val a = Iterator.iterate(1)(x => {Thread.sleep(1000); x+1})
      

      Iterator 在您需要处理大数据时非常有用。您也可以实现自己的:

      val it = new Iterator[Int] {
        var i = -1
        def hasNext = true
        def next(): Int = { i += 1; i }
      }
      

      【讨论】:

        【解决方案4】:

        我没有看到任何我可以用它做的事情,而这对于 Iterable 是不可能的

        其实大多数collection能做的也可以用Array来做,只是我们不这样做,因为它不方便

        同样的道理也适用于迭代器,如果你想对可变状态建模,那么迭代器更有意义。

        例如,Random 的实现方式类似于迭代器,因为它在迭代器中更自然地适合用例,而不是可迭代。

        【讨论】:

          猜你喜欢
          • 2013-06-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-27
          • 1970-01-01
          • 1970-01-01
          • 2011-09-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多