Comparing 2 case class instances in scala

Viewed 190

I have a case class lets say Person(name:String,age:Int,address:String) and i have a list of its instances.

object HelloWorld {
   def main(args: Array[String]) {
      case class Person(name: String,age: Int,location :String)
      val per1=Person("gaurav",21,"chennai")
      val per2=Person("gaurav",21,"pune")
      
      val per3=Person("sur",26,"delhi")
      
      val lst=per1::per2::per3::Nil
}
}

How shall i compare the instances of this case class only on two of its fields say name and age and remove any duplicates if i find any?

2 Answers

If you're on Scala 2.13.x you can use distinctBy().

List(Person("gaurav",21,"chennai")
    ,Person("gaurav",21,"pune")
    ,Person("sur",26,"delhi"))
  .distinctBy(p => (p.name,p.age))
//res0: List[Person] = List(Person(gaurav,21,chennai), Person(sur,26,delhi))

pre-Scala 2.13.x

Without distinctBy() I'd probably go with folding over the List to build the result.

....foldLeft((List.empty[Person],Set.empty[(String,Int)])){
     case ((acc,seen), prsn@Person(nm,age,_)) => 
       if (seen(nm -> age)) (acc, seen)
       else (prsn::acc, seen+(nm -> age))
   }._1.reverse
//same result

You can just use some cache and foldLeft:

val (_, distinctLst) = lst.foldLeft(Set.empty[(String, Int)] -> Vector.empty[Person]){
  case ((metPersons, persons), nextPerson) if metPersons.contains(nextPerson.name -> nextPerson.age) => metPersons -> persons
  case ((metPersons, persons), nextPerson) => (metPersons + (nextPerson.name -> nextPerson.age)) -> (persons :+ nextPerson)
}
println(distinctLst.toList) // List(Person(gaurav,21,chennai), Person(sur,26,delhi))

or you can override equals and hashCode methods for Person but be careful it will change Person behavior for the whole program.

case class Person(name: String, age: Int, location: String) {
  override def equals(o: Any): Boolean =
    o match {
      case Person(n, a, _) => n == name && a == age
      case _ => false
    }

  override def hashCode(): Int = (name -> age).hashCode()
}

val per1 = Person("gaurav", 21, "chennai")
val per2 = Person("gaurav", 21, "pune")
println(per1 == per1) // true
println(per1 == per2) // true

val per3 = Person("sur", 26, "delhi")
val lst = per1 :: per2 :: per3 :: Nil
println(lst.distinct) // List(Person(gaurav,21,chennai), Person(sur,26,delhi))
Related