In Scala, is there a neat and simple way to compare one value with multiple values

試著忘記壹切 提交于 2019-12-05 11:00:06

问题


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.


回答1:


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)



回答2:


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



回答3:


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)



回答4:


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.




回答5:


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.




回答6:


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




回答7:


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)


来源:https://stackoverflow.com/questions/5927608/in-scala-is-there-a-neat-and-simple-way-to-compare-one-value-with-multiple-valu

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!