5 ответов:
С Scala docs:
Примечание: разница между
c filter pиc withFilter pв том, что бывший создает новую коллекцию, в то время как последняя ограничивает только домен последующиеmap,flatMap,foreachиwithFilterоперации.так
filterвозьмет оригинальную коллекцию и произведет новую коллекцию, ноwithFilterбудет не строго (т. е. лениво) передавать нефильтрованные значения до конца позжеmap/flatMap/withFilterвызовы, сохранение второго прохода через (отфильтрованную) коллекцию. Следовательно, это будет более эффективно при переходе к этим последующим вызовам метода.в самом деле
withFilterспециально разработан для работы с цепочками этих методов, что является то, что для понимания де-сахаром В. Никаких других методов (таких какforall/exists), необходимых для этого, поэтому они не были добавлены кFilterMonadicтип возвращаемогоwithFilter.
в дополнение к отличный ответ 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-comprehension переводится вval result = list withFilter { case i => go } map { case i => { go = false i } }как вы можете видеть, перевод преобразует условие в вызов
withFilter. До Scala 2.8, for-comprehension были переведены на что-то вроде следующего: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метод.ссылка: - p.120, Scala in action (обложки Scala 2.10), Manning Publications, Milanjan Raychaudhuri - мысли Одерского о переводе для понимания
основная причина, потому что forall / существует не реализованы в том, что случай использования таков:
- вы можете лениво применить withFilter к бесконечному потоку / iterable
- вы можете лениво применить другой withFilter (и снова и снова)
для реализации 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 по-прежнему является итератором. только когда мы называем в список случайные числа будут генерироваться и фильтруется в цепи
отметим, что карта(удостоверение) эквивалентно карта (i= > i) и он используется здесь для преобразования объекта withFilter обратно в исходный тип (например , коллекция, поток, итератор)
использование для yield может быть обходным, например:
for { e <- col; if e isNotEmpty } yield e.get(0)
в качестве обходного пути, вы можете выполнять другие функции с только
mapиflatMap.кроме того, эта оптимизация бесполезна для небольшой коллекции...
Comments