如果您list
变成一个惰性集合,例如 an Iterator
,那么您可以一次性应用所有过滤器操作(或其他类似的操作map
):
val list = (1 to 12).toList
val doubleFiltered: List[Int] =
list.iterator
.filter(_ % 2 == 0)
.filter(_ % 3 == 0)
.toList
println(doubleFiltered)
当您使用 将集合转换为 Iterator 时.iterator
,Scala 将跟踪要执行的操作(这里是两个filter
s),但会等待执行它们直到实际访问结果(这里是通过对 的调用.toList
)。
所以我可能会像这样重写你的代码:
val list = (1 to 12).toList
val evens = list.iterator.filter(_ % 2 == 0)
val result =
if(someCondition)
evens.filter(_ % 3 == 0)
else
evens.filter(_ % 5 == 0)
result foreach println
根据您想要做什么,您可能需要一个Iterator
、一个Stream
或一个View
。它们都是惰性计算的(因此将应用一次性方面),但它们在是否可以多次迭代(Stream
和View
)或是否保留计算值以供以后访问(Stream
)等方面有所不同。
要真正看到这些不同的惰性行为,请尝试运行这段代码并设置<OPERATION>
为toList
、iterator
、view
或toStream
:
val result =
(1 to 12).<OPERATION>
.filter { e => println("filter 1: " + e); e % 2 == 0 }
.filter { e => println("filter 2: " + e); e % 3 == 0 }
result foreach println
result foreach println
这是您将看到的行为:
List
(或任何其他非惰性集合):每个filter
都需要对集合进行单独的迭代。生成的过滤集合存储在内存中,以便每个foreach
都可以显示它。
Iterator
: filter
s 和 firstforeach
都是在一次迭代中完成的。第二个foreach
什么都不做,因为Iterator
已经消耗了。结果不存储在内存中。
View
:这两个foreach
调用都会导致它们自己对集合进行单遍迭代以执行filters
. 结果不存储在内存中。
Stream
: filter
s 和 firstforeach
都是在一次迭代中完成的。生成的过滤集合存储在内存中,以便每个foreach
都可以显示它。