Чи завжди ефективніше використовувати 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)