필터 대신 withFilter


답변:


121

에서 스칼라 문서 :

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

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

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


언젠가 여전히 이러한 방법을 추가하기를 바랍니다.
Kigyo

1
@Kigyo 나는 당신이 withFilter를 직접 사용해야한다고 생각하지 않습니다 (암묵적으로 for-expressions 내에서 제외). view지도 / 필터가 게 으르도록 하려면 사용 합니다.
Luigi Plinge 2013 년

내가 참조. view과 의 정확한 차이점은 withFilter무엇입니까? 보기가 사용되지 않는 이유는 무엇 for-loops입니까?
Kigyo

5
참고로 Collections-Tips and Tricks 가 뛰어난 정보를 제공 한다고 생각합니다 . H5는 고정되어 있지 않지만 Don’t create temporary collections링크 된 섹션에서 검색 할 수 있습니다 .
sthzg

4
의 명시적인 사용과 관련하여 withFilterMartin Odersky는 Coursera의 Scala 과정에서 명시 적으로 사용합니다. 그가 그렇게한다는 점을 감안할 때, 그 차이는 일반적으로 한 캐릭터에 불과하지만 다른 사람들도 그렇게하는 것에 대해 위로를 줄 수 있습니다. 예를 들어 seq.view filter pseq withFilter p.
Chuck Daniels

9

의 또한 어둠의 땅의 우수한 대답 , 나는 사이의 차이의 직관적 인 예를 가지고 싶습니다 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의 생각


1

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

  • 무한 스트림 / 반복 가능에 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 를 호출 할 때만 난수가 생성되고 체인으로 필터링됩니다.

참고 지도 (신원) 에 해당 매핑 (I => I) 및 원래 형으로 withFilter 오브젝트 다시 전환하기 위해 여기에 (예를 들어 수집 스트림, 반복자)를 사용


1

forall / exists 부분의 경우 :

someList.filter(conditionA).forall(conditionB)

(조금 직관적이지 않지만)

!someList.exists(conditionA && !conditionB)

마찬가지로, .filter (). exists ()는 하나의 exists () 검사로 결합 될 수 있습니까?



-5

해결 방법으로 map및 만 사용 하여 다른 함수를 구현할 수 있습니다 flatMap.

게다가이 최적화는 소규모 컬렉션에서는 쓸모가 없습니다…

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.