2011-09-28 5 views
17

어떤 연산이 A의 인스턴스에 적용 가능한지 검사하고, 그렇다면 B 또는 None의 인스턴스를 반환하는 함수가 있다고 가정 해 보겠습니다.스칼라 : 옵션 모음 필터링

 def checker[A,B](a: A) : Option[B] = ... 

이제 모든 유효 값을 포함하는 새 컬렉션을 만들고 싶습니다. None 값을 삭제하여 B 인스턴스 다음 코드는 작업을 수행하는 것 같지만 확실한 방법이 있습니다.

 val as = List[A](a1, a2, a3, ...) 
    val bs = 
    as 
    .map((a) => checker(a)) // List[A] => List[Option[B]] 
    .filter(_.isDefined)  // List[Option[B]] => List[Option[B]] 
    .map(_.get)    // List[Option[B]] => List[B] 

고마워요!

+28

flatMap 그 젠장 –

+0

@oxbow_lakes 나는 정확한 견적을 믿는다 : _ "이게 뭐야? 아마추어의 시간? flatMap 그거야!"_ –

+0

그 인용문이 트위터에서 나왔습니까? – huynhjl

답변

25

이 그것을 수행해야합니다

val bs = as.flatMap(checker) 
+0

여러 가지 이유로 저에게 적합하지 않습니다 : 1. 타입 추론, 2. List # flatMap은 GenTraversableOnce를 기대합니다. 올바른 것은 as.flatMap {a => 체커 [A, B] (a)}입니다. – IttayD

+0

'Int'에서'Option [String]'까지 함수로 테스트했습니다. 최악의 경우에는 명시적인 유형을 추가해야합니다. –

+2

은 2.9.1에서 작동합니다. –

10

위의 대답은 정확하지만 당신이 checker를 다시 할 수 있다면, 난 당신이 PartialFunctioncollect 사용하는 것이 좋습니다. PartialFunction는 A 유형의 함수 인 => 여기서 A. 모든 값에 대해 정의 불필요 B 간단한 예이다

scala> List(1, 2, 3, 4, "5") collect {case x : Int => x + 42} 
res1: List[Int] = List(43, 44, 45, 46) 

collect는 인수로 PartialFunction의 인스턴스를 취하고 모든 소자에 적용 수집. 이 경우 함수는 Ints에 대해서만 정의되고 "5"은 필터링됩니다. 따라서 collectmapfilter의 조합입니다. 정확히 일치해야합니다.

+1

'collect'는 실제로'filter'와'map'의 조합이지만, 일반적으로 다른 방향으로는 작동하지 않습니다 ('map' ** then **'filter'). 왜냐하면 case 문을 가드하여 필터를 정의해야하기 때문이다. 따라서 OP의 마지막 두 문장 ('.collect {case Some (x) => x}')을 대체하는 것이 좋겠지 만'checker'가 어떤 종류의 중요한 계산을 포함하여 'Some' 또는'None'을 사용하면 부분 함수로 쓰는 것이 어려울 수 있습니다. –