Всегда ли эффективнее использовать withFilter вместо filter при последующем применении таких функций, как карта, плоская карта и т. Д.?
Почему поддерживаются только map, flatmap и foreach? (Ожидаемые функции типа forall / также существуют)
Всегда ли эффективнее использовать withFilter вместо filter при последующем применении таких функций, как карта, плоская карта и т. Д.?
Почему поддерживаются только map, flatmap и foreach? (Ожидаемые функции типа forall / также существуют)
Ответы:
Из документации Scala :
Таким образом,
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)
. Так обстоит дело с Scala 2.8, потому что for-complation переведен наval result = list withFilter { case i => go } map { case i => { go = false i } }
Как видите, перевод преобразует условие в вызов
withFilter
. В предыдущих версиях Scala 2.8 функция for-computing была переведена примерно так: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, Scala в действии (охватывает Scala 2.10), Manning Publications, Миланян Райчаудхури - мысли Одерского о переводе для понимания
источник
Основная причина того, что forall / exists не реализован, заключается в следующем:
Для реализации forall / exists нам нужно получить все элементы, не теряя лени.
Так например:
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 обратно в исходный тип (например, коллекция, поток, итератор)
источник
Для части forall / exists:
будет то же самое (хотя и немного неинтуитивно)
Точно так же .filter (). Exists () можно объединить в одну проверку exists ()?
источник
Использование для yield может быть обходным решением, например:
for { e <- col; if e isNotEmpty } yield e.get(0)
источник
В качестве обходного пути вы можете реализовать другие функции только с помощью
map
иflatMap
.Более того, эта оптимизация бесполезна для небольших коллекций…
источник