Ответ 1
Если вы превратите list
в ленивую коллекцию, например, 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
, a 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
и первыйforeach
выполняются в одной итерации. Второйforeach
ничего не делает с момента потребленияIterator
. Результаты не сохраняются в памяти. -
View
: Оба вызоваforeach
приводят к их собственной однопроходной итерации по коллекции для выполненияfilters
. Результаты не сохраняются в памяти. -
Stream
: Иfilter
, и первыйforeach
выполняются за одну итерацию. Полученная фильтрованная коллекция сохраняется в памяти, так что каждыйforeach
может просто отображать ее.