查找scala列表中的元素,并且还知道哪个谓词已满足

时间:2010-02-01 10:09:34

标签: list scala find predicate

我在scala中遇到以下问题。我必须找到al list中的第一个元素,它满足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)))

结果是:

Some(B)
Some(AA)

对于l1的情况,我希望有一些返回值(例如一个字符串)表示满足c1(对于l2情况,c2)。 一个可能的解决方案可能是在测试之前定义一个var并将其设置在c1和c2函数中,但我想找到一个更“功能样式”的解决方案,也许会返回一个像元组的东西:(元素找到,条件满足)。

提前感谢您的帮助

3 个答案:

答案 0 :(得分:9)

我会这样做:

Scala 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)

Scala 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确保映射将按需完成,而不是应用于整个列表。

答案 1 :(得分: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))

根据您的要求,您可以使用参数Map [T => Boolean,String],用于返回标签字符串:def find[T](l1 : List[T], fs : Map[T => Boolean, String])或定义自己的运算符。

这将评估找到第一个元素的中止的整个列表。

答案 2 :(得分:1)

以下是丹尼尔(和Retronym的)答案的变体。

如果您只想要成功的谓词(列表中),那么您可以使用

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 )
}

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,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的代码;将2.7的“视图”切换为“投影”。)