In Scala, is there a neat and simple way to compare one value with multiple values
Say I have a variable x, and I want to check if it's equal to any one of multiple values a, b, c, d, e (I mean the == equality, not identity).
In an SQL query the same concept is handled with
WHERE x IN (a, b, c, d, e).
Is there something equivalent in Scala that's 开发者_JS百科as straightforward as that? I know it's otherwise possible to do it in one line with a complex expression such as building a HashSet and checking for existence in the set, but I'd prefer to use a simple construct if it's available.
You could implement an in
operator as follows:
scala> implicit def anyWithIn[A](a: A) = new {
| def in(as: A*) = as.exists(_ == a)
| }
anyWithIn: [A](a: A)java.lang.Object{def in(as: A*): Boolean}
scala> 5 in (3, 4, 9, 11)
res0: Boolean = false
scala> 5 in (3, 4, 9, 11, 5)
res1: Boolean = true
I would prefer contains(a)
over exists(_ == a)
:
scala> List(3, 4, 5) contains 4
res0: Boolean = true
scala> List(3, 4, 5) contains 6
res1: Boolean = false
Update: contains
is defined in SeqLike
, so the above works with any sequence.
Update 2: Here is the definition of contains
in SeqLike
:
def contains(elem: Any): Boolean = exists (_ == elem)
Given that a Set[A]
is also a A => Boolean
, you can just say:
Set(a, b, c, d, e) apply x
It's actually quite nice to define some pimpin' sugar for this:
class PredicateW[A](self : A => Boolean) {
def ∈:(a : A) = self apply a
}
implicit def pred2wrapper[A](p : A => Boolean) = new PredicateW(p)
Then you can write the code like so:
x ∈: Set(a, b, c, d, e)
By synthesizing all the other answers, I have come up with the correct answer:
implicit def anyWithIn[A](a: A) = new {
def ∈(as: A*) = as.contains(a)
}
anyWithIn: [A](a: A)java.lang.Object{def ?(as: A*): Boolean}
5 ∈ (1,3,5)
res1: Boolean = true
Ta-da.
exists:
List (3, 4, 5).exists (_ == 4)
// res20: Boolean = true
find and filter come close:
List (3, 4, 5).find (_ == 4)
// res16: Option[Int] = Some(4)
List (3, 4, 5).filter (_ == 4)
// res17: List[Int] = List(4)
My first answer was, as other answers, to use contain:
List (3, 4, 5).contains (4)
but then I thought, it would only work for boxed values like 4, not for classes, which distinguish identity and equality. To prove it, I wrote a small class, which proved me wrong: :)
class Ue (val i: Int) {
override def equals (other: Any) = other match {
case o: Ue => i == o.i
case _ => false }
}
val a = new Ue (4)
// a: Ue = Ue@1e040e5
val b = new Ue (4)
// b: Ue = Ue@1a4548b (no identity)
a == b
// res110: Boolean = true (surprise?)
a.equals (b)
// res112: Boolean = true (expected)
a.eq (b)
// res113: Boolean = false (expected)
List (a).contains (b)
// res119: Boolean = true (surprise)
List (a).exists (_ == b)
// res120: Boolean = true (expected)
List (a).exists (_ .eq (b))
// res121: Boolean = false (expected)
I see, I have to use equals/eq/== more often, to get the distinctions into my brain.
List (3, 4, 5).contains (4)
is imho the answer which is most easy.
Set(a, b, c, d, e)(x)
works as well. I'll leave the reasons for it as an exercise to the reader. :-)
class Ue (val i: Int) {
override def equals (other: Any) = other match {
case o: Ue => i == o.i
case _ => false }
}
val a = new Ue (4)
// a: Ue = Ue@1e040e5
val b = new Ue (4)
// b: Ue = Ue@1a4548b (no identity)
a == b
// res110: Boolean = true (surprise?)
a.equals (b)
// res112: Boolean = true (expected)
a.eq (b)
// res113: Boolean = false (expected)
List (a).contains (b)
// res119: Boolean = true (surprise)
List (a).exists (_ == b)
// res120: Boolean = true (expected)
List (a).exists (_ .eq (b))
// res121: Boolean = false (expected)
精彩评论