交错迭代器

时间:2016-08-24 21:42:50

标签: scala iterator

我编写了以下代码,期望最后一个print方法显示两个迭代器的元素组合。相反,它只显示perfectSquares的元素。有人可以向我解释一下吗?

object Fuge {

  def main(args: Array[String]) : Unit = {

    perfectSquares.takeWhile(_ < 100).foreach(square => print(square + " "))
    println()
    triangles.takeWhile(_ < 100).foreach(triangle => print(triangle + " "))
    println()
    (perfectSquares++triangles).takeWhile(_ < 100).foreach(combine => print(combine + " "))

  }

  def perfectSquares : Iterator[Int] = {
    Iterator.from(1).map(x => x * x)
  }

  def triangles : Iterator[Int] = {
    Iterator.from(1).map(n => (n * (n + 1)/2))
  }

}

输出

1 4 9 16 25 36 49 64 81    
1 3 6 10 15 21 28 36 45 55 66 78 91 
1 4 9 16 25 36 49 64 81 

2 个答案:

答案 0 :(得分:2)

来自takeWhile的文档:

  /** Takes longest prefix of values produced by this iterator that satisfy a predicate.
   *
   *  @param   p  The predicate used to test elements.
   *  @return  An iterator returning the values produced by this iterator, until
   *           this iterator produces a value that does not satisfy
   *           the predicate `p`.
   *  @note    Reuse: $consumesAndProducesIterator
   */

这意味着迭代器在那个时刻停止了。你创建的是一个远远超过100的迭代器,然后在某个时刻再次从1开始。但是takeWhile不会那么远,因为它已经遇到了高于100的数字。参见:

object Fuge {
  def main(args: Array[String]) : Unit = {

    perfectSquares.takeWhile(_ < 100).foreach(square => print(square + " "))
    println()
    triangles.takeWhile(_ < 100).foreach(triangle => print(triangle + " "))
    println()
    def interleave (a: Iterator[Int], b: Iterator[Int]): Stream[Int] = {
      if (a.isEmpty || b.isEmpty) { Stream.empty }
      else {
        a.next() #:: b.next() #:: interleave(a, b)
      }
    }
    lazy val interleaved = interleave(perfectSquares, triangles)
    interleaved.takeWhile(_ < 100).foreach(combine => print(combine + " "))
  }

  def perfectSquares : Iterator[Int] = {
    Iterator.from(1).map(x => x * x)
  }

  def triangles : Iterator[Int] = {
    Iterator.from(1).map(n => (n * (n + 1)/2))
  }
}

这里我使用流来懒惰地评估整数序列。通过这种方式,我们可以确保交错。请注意,这只是交错的,而不是排序的。

这会产生:

1 4 9 16 25 36 49 64 81 
1 3 6 10 15 21 28 36 45 55 66 78 91 
1 1 4 3 9 6 16 10 25 15 36 21 49 28 64 36 81 45

要在流中进行排序,您需要BufferedIterator并稍微更改interleave功能。这是因为调用next()会使迭代器前进 - 你无法返回。在您需要列表a中的项目之前, 还无法知道列表b中需要多少项,反之亦然。但是BufferedIterator允许你调用head,这是一个'偷看'并且不会推进迭代器。现在代码变为:

object Fuge {
  def main(args: Array[String]) : Unit = {
    perfectSquares.takeWhile(_ < 100).foreach(square => print(square + " "))
    println()
    triangles.takeWhile(_ < 100).foreach(triangle => print(triangle + " "))
    println()
    def interleave (a: BufferedIterator[Int], b: BufferedIterator[Int]): Stream[Int] = {
      if (a.isEmpty || b.isEmpty) { Stream.empty }
      else if (a.head <= b.head){
        a.next() #:: interleave(a, b)
      } else {
        b.next() #:: interleave(a, b)
      }
    }
    lazy val interleaved = interleave(perfectSquares.buffered, triangles.buffered)
    interleaved.takeWhile(_ < 100).foreach(combine => print(combine + " "))
  }

  def perfectSquares : Iterator[Int] = {
    Iterator.from(1).map(x => x * x)
  }

  def triangles : Iterator[Int] = {
    Iterator.from(1).map(n => (n * (n + 1)/2))
  }
}

输出是:

1 4 9 16 25 36 49 64 81 
1 3 6 10 15 21 28 36 45 55 66 78 91 
1 1 3 4 6 9 10 15 16 21 25 28 36 36 45 49 55 64 66 78 81 91

答案 1 :(得分:0)

此处使用Streams的问题在于它们缓存了所有先前的数据。我宁愿按原样交错迭代器,而不涉及流。 像这样:

class InterleavingIterator[X, X1 <: X, X2 <: X](
    iterator1: Iterator[X1],
    iterator2: Iterator[X2]) extends Iterator[X] {
  private var i2: (Iterator[X], Iterator[X]) = (iterator1, iterator2)

  def hasNext: Boolean = iterator1.hasNext || iterator2.hasNext

  def next: X = {
    i2 = i2.swap
    if (i2._1.hasNext) i2._1.next else i2._2.next
  }
}