在 scala 列表中查找元素并知道满足哪个谓词

发布于 2024-08-19 19:49:50 字数 582 浏览 8 评论 0原文

我在 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)))

结果是:

Some(B)
Some(AA)

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

预先感谢您的帮助

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:

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

Thanks in advance for the help

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

池予 2024-08-26 19:49:50

我会这样做:

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)

视图/投影确保映射将按需完成,而不是应用于整个列表。

I'd do this:

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)

The view/projection ensures that the mapping will be done on-demand, instead of being applied to the whole list.

饮惑 2024-08-26 19:49:50
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]) 或定义您自己的运算符。

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

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.

This will evaluate the whole list where find aborts for the first element found.

独自唱情﹋歌 2024-08-26 19:49:50

这是 Daniel(和 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 的“视图”切换为“投影”。)

Here's a variant on Daniel's (and Retronym's) answer(s).

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文