List 在scala列表中查找元素,并知道满足了哪个谓词
我在scala中有以下问题。我必须找到al列表中的第一个元素,它满足OR中有两个条件的谓词函数。问题是我想得到元素,但也知道这两个条件中的哪一个已经满足。下面是一个简单的例子:List 在scala列表中查找元素,并知道满足了哪个谓词,list,scala,find,predicate,List,Scala,Find,Predicate,我在scala中有以下问题。我必须找到al列表中的第一个元素,它满足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
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得到满足(c2用于l2情况)。
一个可能的解决方案是在测试之前定义一个var,并在c1和c2函数中设置它,但我想找到一个更“功能化”的解决方案,可能是返回元组的东西,如:(element find,condition suited)
提前谢谢你的帮助
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])
或定义您自己的运算符
这将评估find为找到的第一个元素中止的整个列表。我会这样做:
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)
视图
/投影
确保映射将按需完成,而不是应用于整个列表。以下是Daniel(和追溯者)答案的变体
如果您只希望谓词(从列表中)成功,那么可以使用
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))))
(这是2.8的代码;将2.7的“视图”切换为“投影”)泛化为谓词列表
def findPredsOr[T](l:list[T],ps:list[T=>Boolean]):Option[(T,list[Boolean])=l.view.map(el=>(el,ps.map(u.apply(el)))。find(T=>T.2.contains(true))
伟大的解决方案。感谢您让我发现视图/投影,它似乎非常有用!
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
}
}