2010-02-01 4 views
10

다음과 같은 문제가 있습니다. 나는 OR리스트에서 두 개의 조건을 가진 술어 함수를 만족시키는 첫 번째 요소를 찾아야 만한다. 문제는 요소를 얻고 싶지만 두 조건 중 어느 것이 만족 했는지도 알고 싶습니다.스칼라 목록에서 요소를 찾고 어떤 술어가 만족되었는지도 알 수 있습니다.

val l1 = List("A", "B", "AA", "BB") 
val l2 = List("AA", "BB", "A", "B") 

def c1(s: String) = s.startsWith("B") 
def c2(s: String) = s.length == 2 

println(l1.find(s => c1(s) || c2(s))) 
println(l2.find(s => c1(s) || c2(s))) 

결과이다 : 일부 리턴 값 (예를 들어, 문자열) 싶은 L1 케이스

Some(B) 
Some(AA) 

C1을 위해 (C2 만족되었음을 나타내는 여기서 간단한 예이고 12 사례). 가능한 해결책은 테스트 전에 var를 정의하고 c1 및 c2 함수 내에서 설정할 수 있지만 좀 더 "기능 스타일"솔루션을 찾고 싶습니다. 다음과 같이 터플을 반환하는 뭔가가있을 수 있습니다. (요소를 발견했습니다., 조건 만족). def find[T](l1 : List[T], fs : Map[T => Boolean, String])를하거나 자신의 연산자를 정의 : 요구 사항에 따라 도움

답변

9

나는이 작업을 수행 할 것 :

스칼라 2.8 :

def find2p[T](l: List[T], p1: T => Boolean, p2: T => Boolean) = 
    l.view.map(el => (el, p1(el), p2(el))).find(t => t._2 || t._3) 

스칼라 2.7 :

def find2p[T](l: List[T], p1: T => Boolean, p2: T => Boolean) = 
    l.projection.map(el => (el, p1(el), p2(el))).find(t => t._2 || t._3) 

view/projection 맵핑 대신, 주문형 할 것을 보장 전체 목록에 적용됩니다.

+0

술어의 목록에 일반화'def findPredsOr [T] (l :리스트 [T], ps :리스트 [T => 부울]) : 옵션 [(T , list [Boolean])] = l.view.map (엘, ps.map (_. apply (el)))) find (t => t._2.contains (true))' – retronym

+0

그레이트 솔루션. 보기/투영을 발견해 주셔서 감사합니다. 매우 유용합니다! –

3
def find[T](l1 : List[T], c1 : T => Boolean, c2 : T => Boolean) = ((None : Option[(String, T)]) /: l1)((l, n) => l match { 
    case x : Some[_] => l 
    case x if c1(n) => Some("c1", n) 
    case x if c2(n) => Some("c2", n) 
    case _ => None 
}) 

scala> find(l1, c1, c2) 
res2: Option[(String, java.lang.String)] = Some((c1,B)) 

scala> find(l2, c1, c2) 
res3: Option[(String, java.lang.String)] = Some((c2,AA)) 

에 미리

덕분에 당신은 반환 레이블 문자열에 대한 매개 변수 맵 [T => 부울, 문자열]을 가질 수있다.

그러면 발견 된 첫 번째 요소에 대해 검색이 중단되는 전체 목록이 평가됩니다.

1

다음은 Daniel (및 Retronym)의 답변에 대한 변형입니다.

def findP[T](list: Iterable[T],preds: Iterable[(T=>Boolean,String)]) = { 
    list.view.map(x => (x , preds.find(_._1(x)))).find(_._2.isDefined) 
} 

scala> findP(
    | List(1,2,3,4,5,6), 
    | List(((i:Int)=>i>4,"Fred") , ((i:Int)=>(i%6)==0,"Barney")) 
    |) 
res2: Option[(Int, Option[((Int) => Boolean, String)])] = 
    Some((5,Some((<function1>,Fred)))) 

결과 : 당신은 그냥 성공이 (목록에서) 술어를 원하는 경우

, 당신은

def findP[T](list: Iterable[T], preds: Iterable[T=>Boolean]) = { 
    list.view.map(x => (x , preds.find(_(x)))).find(_._2.isDefined) 
} 

대안으로 사용할 수 있습니다, 당신은 이름 술어의 목록을 사용할 수 있습니다 어지러워 조금,하지만 당신은 질문을 정확하게 줄을 쉽게 충분히 풀어 수 있습니다에 대한 :

def findP[T](list: Iterable[T],preds: Iterable[(T=>Boolean,String)]) = { 
    list.view.map(x => (x , preds.find(_._1(x)))).find(_._2.isDefined) match { 
    case Some((i,Some((_,s)))) => Some((i,s)) 
    case _ => None 
    } 
} 

(이것은 2.8 용 코드입니다.

관련 문제