Всегда ли более эффективно использовать withFilter вместо фильтра, когда впоследствии применяют такие функции, как map, flatmap и т.д.?
Почему поддерживаются только карта, плоская карта и foreach? (Ожидаемые функции, такие как forall/существуют также)
Ответ 1
Из документов Scala:
Примечание: разница между c filter p
и c withFilter p
заключается в том, что первый создает новую коллекцию, в то время как последняя ограничивает домен последующие операции map
, flatMap
, foreach
и withFilter
.
Таким образом, filter
возьмет исходную коллекцию и создаст новую коллекцию, но withFilter
будет не строго (то есть лениво) передавать нефильтрованные значения последующим вызовам map
/flatMap
/withFilter
, сохраняя второй проход через (отфильтрованную) коллекцию. Следовательно, он будет более эффективным при переходе к последующим вызовам методов.
На самом деле, withFilter
специально разработан для работы с цепочками этих методов, и именно для этого десагарируется понимание. Никаких других методов (таких как forall
/exists
) для этого не требуется, поэтому они не были добавлены к типу возврата FilterMonadic
withFilter
.
Ответ 2
Помимо превосходного ответа 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, потому что для понимания это переведено на
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, Scala в действии (охватывает Scala 2.10), Manning Publications, Миланян Райчаудхури - Одерские мысли о понятном переводе
Ответ 3
Основная причина того, что forall/exist не реализована, заключается в том, что сценарий использования:
- Вы можете лениво применять 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 все еще является итератором. Только, когда мы вызываем toList, случайные числа будут генерироваться и фильтроваться в цепочке
Обратите внимание, что map (identity) эквивалентно map (i => i) и используется здесь для преобразования объекта withFilter обратно в исходный тип (например, коллекция, поток, итератор).
Ответ 4
Для части/существует часть:
someList.filter(conditionA).forall(conditionB)
будет таким же, как (хотя и немного не интуитивно понятно)
!someList.exists(conditionA && !conditionB)
Точно так же .filter(). exist() можно объединить в одну проверку there()?
Ответ 5
Использование для урока может быть выполнено, например:
for {
e <- col;
if e isNotEmpty
} yield e.get(0)
Ответ 6
В качестве обходного пути вы можете реализовать другие функции только с map
и flatMap
.
Кроме того, эта оптимизация бесполезна для небольших коллекций...