我编写了以下代码,期望最后一个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
答案 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
}
}