Чи завжди ефективніше використовувати withFilter замість фільтра, коли згодом застосовуються такі функції, як map, flatmap тощо?
Чому підтримуються лише карти, плоскі карти та foreach? (Очікувані функції, такі як forall / також існують)
Чи завжди ефективніше використовувати withFilter замість фільтра, коли згодом застосовуються такі функції, як map, flatmap тощо?
Чому підтримуються лише карти, плоскі карти та foreach? (Очікувані функції, такі як forall / також існують)
Відповіді:
З документів Scala :
Примітка: різниця між
c filter p
іc withFilter p
в тому , що колишній створює нову колекцію, в той час як останній тільки обмежує область наступнихmap
,flatMap
,foreach
іwithFilter
операцій.
Тож filter
візьмемо оригінальну колекцію і випустимо нову колекцію, алеwithFilter
буде нестрого (тобто ліниво) передавати нефільтровані значення на наступні map
/ flatMap
/ withFilter
виклики, зберігаючи другий прохід через (фільтровану) колекцію. Отже, це буде більш ефективно при переході до наступних викликів методів.
Насправді, withFilter
він спеціально розроблений для роботи з ланцюжками цих методів, саме на це де-цукор для розуміння. Для цього не потрібні інші методи (наприклад, forall
/ exists
), тому вони не були додані до FilterMonadic
типу повернення withFilter
.
view
якщо ви хочете, щоб карти / фільтри були лінивими.
view
та withFilter
? Чому не використовується перегляд for-loops
?
Don’t create temporary collections
у зв’язаному розділі.
withFilter
, то сам Мартін Одерський явно використовує його у своїх курсах Scala на Coursera, що я дуже рекомендую. Враховуючи, що він робить це, це може дати іншим комфорт, роблячи це, хоча різниця, як правило, становить лише 1 символ. Наприклад seq.view filter p
проти seq withFilter p
.
На додаток до чудової відповіді Shadowlands , я хотів би навести інтуїтивний приклад різниці між filter
і withFilter
.
Давайте розглянемо наступний код
val list = List(1, 2, 3)
var go = true
val result = for(i <- list; if(go)) yield {
go = false
i
}
Більшість людей розраховують result
на рівне List(1)
. Це стосується шкали 2.8, оскільки перекладено для розуміння
val result = list withFilter {
case i => go
} map {
case i => {
go = false
i
}
}
Як бачите, переклад перетворює умову у виклик withFilter
. До Scala 2.8, для розуміння було перекладено приблизно так:
val r2 = list filter {
case i => go
} map {
case i => {
go = false
i
}
}
Використовуючи filter
значення result
буде досить різні: List(1, 2, 3)
. Той факт, що ми робимо go
прапор false
, ніяк не впливає на фільтр, оскільки фільтр уже зроблено. Знову ж таки, у Scala 2.8 це питання вирішується за допомогою withFilter
. При withFilter
використанні умова оцінюється кожного разу, коли елемент отримує доступ всередині map
методу.
Довідково : - стор. 120, Скала в дії (охоплює Скалу 2.10), Публікації Меннінга, Міланджан Райчаудхурі - Думки Одерського про переклад для розуміння
Основна причина, оскільки forall / Існує не реалізована, полягає в тому, що варіант використання полягає в тому, що:
Для реалізації forall / існує нам потрібно отримати всі елементи, втрачаючи лінь.
Так наприклад:
import scala.collection.AbstractIterator
class RandomIntIterator extends AbstractIterator[Int] {
val rand = new java.util.Random
def next: Int = rand.nextInt()
def hasNext: Boolean = true
}
//rand_integers is an infinite random integers iterator
val rand_integers = new RandomIntIterator
val rand_naturals =
rand_integers.withFilter(_ > 0)
val rand_even_naturals =
rand_naturals.withFilter(_ % 2 == 0)
println(rand_even_naturals.map(identity).take(10).toList)
//calling a second time we get
//another ten-tuple of random even naturals
println(rand_even_naturals.map(identity).take(10).toList)
Зауважте, що ten_rand_even_naturals все ще є ітератором. Тільки тоді, коли ми зателефонуємо toList, випадкові числа будуть генеровані та відфільтровані в ланцюжку
Зверніть увагу, що map (identity) еквівалентний map (i => i), і він використовується тут для перетворення об'єкта withFilter назад у вихідний тип (наприклад, колекція, потік, ітератор)
Використання для врожайності може бути обхідним шляхом, наприклад:
for {
e <- col;
if e isNotEmpty
} yield e.get(0)