Gigatron
Gigatron

Reputation: 2055

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

Upvotes: 18

Views: 16283

Answers (8)

Marcus
Marcus

Reputation: 2121

Solution which also works with Scala 3:

implicit class PowerAny[A](a: A) {
  /**
   * 2 in (1,2,3,"foo") -> true
   *
   * 4 in (1,2,3,"foo") -> false
   */
  def in(seq: A*): Boolean = seq.contains(a)
}

(My request to update one of the other solutions was rejected.)

Upvotes: 0

king of codex
king of codex

Reputation: 1

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)

Upvotes: 0

Frank S. Thomas
Frank S. Thomas

Reputation: 4785

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)

Upvotes: 22

user unknown
user unknown

Reputation: 36260

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.

Upvotes: 5

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297265

Set(a, b, c, d, e)(x) works as well. I'll leave the reasons for it as an exercise to the reader. :-)

Upvotes: 4

Michael Lorton
Michael Lorton

Reputation: 44416

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.

Upvotes: 11

oxbow_lakes
oxbow_lakes

Reputation: 134310

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)

Upvotes: 12

missingfaktor
missingfaktor

Reputation: 92076

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

Upvotes: 24

Related Questions