如何使用Scala在一次传递中找到满足两个谓词的两个元素?

时间:2014-07-24 14:01:16

标签: scala collections

假设有一个List[A]和两个谓词p1: A => Booleanp2: A => Boolean
我需要在列表中找到两个元素:第一个元素a1满足p1,第一个元素a2满足p2(在我的情况下a1 != a2)< / p>

显然,我可以运行find两次,但我想在一次传递中执行此操作。你会如何在Scala中一次性完成?

3 个答案:

答案 0 :(得分:1)

scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)

scala> val p1 = {x:Int =>  x % 2 == 0}
p1: Int => Boolean = <function1>

scala> val p2 = {x:Int =>  x % 3 == 0}
p2: Int => Boolean = <function1>

scala> val pp = {x:Int => p1(x) || p2(x) }
pp: Int => Boolean = <function1>

scala> l.find(pp)
res2: Option[Int] = Some(2)

scala> l.filter(pp)
res3: List[Int] = List(2, 3)

答案 1 :(得分:1)

这对你有用吗?

def predFilter[A](lst: List[A], p1: A => Boolean, p2: A => Boolean): List[A] =
  lst.filter(x => p1(x) || p2(x)) // or p1(x) && p2(x) depending on your need

这将返回一个与谓词匹配的新列表。

val a = List(1,2,3,4,5)
val b = predFilter[Int](a, _ % 2 == 0, _ % 3 == 0) // b is now List(2, 3, 4)

答案 2 :(得分:1)

所以,这是一次尝试。将它概括为一个谓词列表(并返回找到的元素列表)是相当简单的。

def find2[A](xs: List[A], p1: A => Boolean, p2: A => Boolean): (Option[A], Option[A]) = {
  def find2helper(xs: List[A], p1: A => Boolean, p2: A => Boolean, soFar: (Option[A], Option[A])): (Option[A], Option[A]) = {
    if (xs == Nil) soFar
    else {
      val a1 = if (soFar._1.isDefined) soFar._1 else if (p1(xs.head)) Some(xs.head) else None
      val a2 = if (soFar._2.isDefined) soFar._2 else if (p2(xs.head)) Some(xs.head) else None
      if (a1.isDefined && a2.isDefined) (a1, a2) else find2helper(xs.tail, p1, p2, (a1, a2))
    }
  }
  find2helper(xs, p1, p2, (None, None))

 } //> find2: [A](xs: List[A], p1: A => Boolean, p2: A => Boolean)(Option[A], Option[A])

  val foo = List(1, 2, 3, 4, 5) //> foo  : List[Int] = List(1, 2, 3, 4, 5)

  find2[Int](foo, { x: Int => x > 2 }, { x: Int => x % 2 == 0 })
  //> res0: (Option[Int], Option[Int]) = (Some(3),Some(2))
  find2[Int](foo, { x: Int => x > 2 }, { x: Int => x % 7 == 0 })
  //> res1: (Option[Int], Option[Int]) = (Some(3),None)
  find2[Int](foo, { x: Int => x > 7 }, { x: Int => x % 2 == 0 })
  //> res2: (Option[Int], Option[Int]) = (None,Some(2))
  find2[Int](foo, { x: Int => x > 7 }, { x: Int => x % 7 == 0 })
  //> res3: (Option[Int], Option[Int]) = (None,None)

广义版本(我认为实际上略显清晰)

def findN[A](xs: List[A], ps: List[A => Boolean]): List[Option[A]] = {
  def findNhelper(xs: List[A], ps: List[A => Boolean], soFar: List[Option[A]]): List[Option[A]] = {
    if (xs == Nil) soFar
    else {
      val as = ps.zip(soFar).map {
          case (p, e) => if (e.isDefined) e else if (p(xs.head)) Some(xs.head) else None
      }
      if (as.forall(_.isDefined)) as else findNhelper(xs.tail, ps, as)
    }
  }
  findNhelper(xs, ps, List.fill(ps.length)(None))

} //> findN: [A](xs: List[A], ps: List[A => Boolean])List[Option[A]]

val foo = List(1, 2, 3, 4, 5) //> foo  : List[Int] = List(1, 2, 3, 4, 5)

findN[Int](foo, List({ x: Int => x > 2 }, { x: Int => x % 2 == 0 }))
//> res0: List[Option[Int]] = List(Some(3), Some(2))
findN[Int](foo, List({ x: Int => x > 2 }, { x: Int => x % 7 == 0 }))
//> res1: List[Option[Int]] = List(Some(3), None)
findN[Int](foo, List({ x: Int => x > 7 }, { x: Int => x % 2 == 0 }))
//> res2: List[Option[Int]] = List(None, Some(2))
findN[Int](foo, List({ x: Int => x > 7 }, { x: Int => x % 7 == 0 }))
//> res3: List[Option[Int]] = List(None, None)