IT TIP

필터 대신 withFilter

itqueen 2020. 10. 14. 21:31
반응형

필터 대신 withFilter


나중에 map, flatmap 등과 같은 기능을 적용 할 때 필터 대신 withFilter를 사용하는 것이 항상 더 성능이 좋은가요?

map, flatmap 및 foreach 만 지원되는 이유는 무엇입니까? (forall / exists와 같은 예상 기능)


에서 스칼라 문서 :

참고 사이의 차이 c filter pc withFilter p후자는 단지 다음의 영역으로 제한하는 반면, 전자는, 새로운 집합을 생성하는이고 map, flatMap, foreach, 및 withFilter작업.

따라서 filter원래 컬렉션을 가져와 새 컬렉션을 생성하지만 withFilter필터링되지 않은 값을 나중에 map/ flatMap/ withFilter호출에 엄격하게 (즉, 느리게) 전달 하여 (필터링 된) 컬렉션을 통한 두 번째 패스를 절약합니다. 따라서 이러한 후속 메서드 호출을 전달할 때 더 효율적입니다.

사실, withFilter는 이러한 방법의 체인으로 작업하도록 특별히 설계되었으며, 이것이 바로 이해를위한 것입니다. 이를 위해 다른 메서드 (예 : forall/ exists)가 필요하지 않으므로 FilterMonadic반환 유형에 추가되지 않았습니다 withFilter.


의 또한 어둠의 땅의 우수한 대답 , 나는 사이의 차이의 직관적 인 예를 가지고 싶습니다 filterwithFilter.

다음 코드를 살펴 보겠습니다.

val list = List(1, 2, 3)
var go = true
val result = for(i <- list; if(go)) yield {
   go = false
   i
}

대부분의 사람들 resultList(1). 이것은 Scala 2.8 이후의 경우입니다.

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- 이해를위한 번역에 대한 Odersky의 생각


forall / exists 가 구현되지 않은 주된 이유 는 사용 사례가 다음과 같기 때문 입니다.

  • 무한 스트림 / 반복 가능에 withFilter를 느리게 적용 할 수 있습니다.
  • 다른 withFilter를 느리게 적용 할 수 있습니다.

forall / exist 를 구현하려면 게으름을 없애고 모든 요소를 ​​얻어야합니다.

예를 들면 다음과 같습니다.

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 를 호출 할 때만 난수가 생성되고 체인으로 필터링됩니다.

Note that map(identity) is equivalent to map(i=>i) and it is used here in order to convert a withFilter object back to the original type (eg a collection , a stream, an iterator)


For the forall/exists part:

someList.filter(conditionA).forall(conditionB)

would be the same as (though a little bit un-intuitive)

!someList.exists(conditionA && !conditionB)

Similarly, .filter().exists() can be combined into one exists() check?


Using for yield can be a work around, for example:

for {
  e <- col;
  if e isNotEmpty
} yield e.get(0)

As a workaround, you can implement other functions with only map and flatMap.

Moreover, this optimisation is useless on small collections…

참고URL : https://stackoverflow.com/questions/19617378/withfilter-instead-of-filter

반응형