ps0604 ps0604 - 12 days ago 8
Scala Question

Optimize map contains

I have the following condition

if (map.contains(clazz)) {
// .....
}


Where map is defined as
Map[Clazz,String]


And
Clazz
is defined as

case class Clazz(key: String, field1: String, field2: String)


However, the
key
field alone identifies the object, so the comparison of field1 and field2 is redundant. How to optimize the
contains
statement?

Answer

Simple and straight forward way instead of overriding equals and hashCode

Redefine your Clazz like below.

case class Clazz(key: String)(field1: String, field2: String)

This way equals and hashCode methods will be generated with only key in consideration and field1, field2 will be ignored for the equality check.

That means key uniquely determines the clazz instance which is what you want.

Now you can do contains check which will only use key for internally for equality check.

Scala REPL

scala> case class Clazz(key: String)(field1: String, field2: String)
defined class Clazz

scala> val map = Map(Clazz("foo")("apple", "ball") -> "foo", Clazz("bar")("cat", "bat") -> "bar")
map: Map[Clazz, String] = Map(Clazz(foo) -> "foo", Clazz(bar) -> "bar")

scala> map contains Clazz("foo")("moo", "zoo")
res2: Boolean = true

scala> map contains Clazz("bar")("moo", "zoo")
res3: Boolean = true

scala> map contains Clazz("boo")("moo", "zoo")
res4: Boolean = false

Other way is to just override equals and hashCode

case class Clazz(key: String, field1: String, field2: String) {
  override def equals(otherClazz: Any) = that match {
    case otherClazz: Clazz => otherClazz.key.equals(key)
    case _ => false
  }
  override def hashCode = key.hashCode
}

Third way is the least recommended way

Just maintain a Map[String, Clazz] key to Clazz map.

Now you can check contains like below

val keyMap = map.map { case (clazz, _) => clazz.key -> clazz}

keyMap.contains(clazz.key)

When match is successful then you can get the value using the code.

map.get(keyMap(clazz.key)) //this will give Option[String]
Comments