在 Scala 列表中查找元素并知道满足了哪个谓词
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2175873/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Finding elements in a scala list and also know which predicate has been satisfied
提问by Filippo Tabusso
I have the following problem in scala. I have to find the first element in al list which satisfies a predicate function with two conditions in OR. The problem is that I would like to get the element but also know which of the two conditions has been satisfied. Here is a simple example:
我在 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(s => c1(s) || c2(s)))
println(l2.find(s => c1(s) || c2(s)))
result is:
结果是:
Some(B)
Some(AA)
For the l1 case I would like to have some return value (a String for example) indicating that c1 was satisfied (c2 for the l2 case). A possible solution could be to define a var before the test and set it within the c1 and c2 functions, but I would like to find a more "functional style" solution, maybe something that return a Tuple like: (element found, condition satisfied).
对于 l1 情况,我想要一些返回值(例如一个字符串),表明满足 c1(对于 l2 情况下为 c2)。一个可能的解决方案可能是在测试之前定义一个 var 并将其设置在 c1 和 c2 函数中,但我想找到一个更“函数式”的解决方案,也许可以返回一个元组,例如:(找到元素,条件满足)。
Thanks in advance for the help
在此先感谢您的帮助
采纳答案by Daniel C. Sobral
I'd do this:
我会这样做:
Scala 2.8:
斯卡拉 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:
斯卡拉 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)
The view/projectionensures that the mapping will be done on-demand, instead of being applied to the whole list.
本view/projection保证映射将点播来完成的,而不是被应用到整个列表。
回答by Thomas Jung
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))
Depending on your requirements you could have a parameter Map[T => Boolean, String] for the label strings to return: def find[T](l1 : List[T], fs : Map[T => Boolean, String])or define your own operators.
根据您的要求,您可以使用参数 Map[T => Boolean, String] 来返回标签字符串:def find[T](l1 : List[T], fs : Map[T => Boolean, String])或定义您自己的运算符。
This will evaluate the whole list where find aborts for the first element found.
这将评估整个列表,其中 find 中止找到的第一个元素。
回答by Rex Kerr
Here's a variant on Daniel's (and Retronym's) answer(s).
这是 Daniel(和 Retronym)答案的一个变体。
If you just want the predicate (out of a list) that succeeded, then you can use
如果您只想要成功的谓词(从列表中),那么您可以使用
def findP[T](list: Iterable[T], preds: Iterable[T=>Boolean]) = {
list.view.map( x => (x , preds.find( _(x) )) ).find( _._2.isDefined )
}
Alternatively, you could use a list of named predicates:
或者,您可以使用命名谓词列表:
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))))
The result a little cluttered, but can be unwrapped easily enough to give exactly what you asked for:
结果有点混乱,但可以很容易地展开,以提供您所要求的内容:
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
}
}
(This is code for 2.8; switch "view" to "projection" for 2.7.)
(这是 2.8 的代码;对于 2.7,将“视图”切换为“投影”。)

