假设有一个List[A]
和两个谓词p1: A => Boolean
和p2: A => Boolean
。
我需要在列表中找到两个元素:第一个元素a1
满足p1
,第一个元素a2
满足p2
(在我的情况下a1 != a2
)< / p>
显然,我可以运行find
两次,但我想在一次传递中执行此操作。你会如何在Scala中一次性完成?
答案 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)