Randomize
Randomize

Reputation: 9103

How to extract unique elements from a list of classes in Scala

I have a list of case classes and the instances are the same or similar each other. I need to filter out this list from the "duplicates". In Scala, is there anything like this (pseudo code):

myList.unique ((obj1,obj2) => verifySimilitude(obj1,obj2))

def verifySimilitude(obj1:Foo, obj2:Foo):Boolean = // some logic to verify that objects are the same or at least similar

?

It is pretty much a "cartesian" product so I am wondering what it could be a good solution (keeping the code simple) to solve it.

Upvotes: 2

Views: 241

Answers (1)

Aivean
Aivean

Reputation: 10882

There is no such built-in function, but it's easy to create your own. For the sake of the example, I'm assuming Foo is simple String and verifySimilitude compares first characters of two strings.

type Foo = String

def verifySimilitude(obj1: Foo, obj2: Foo): Boolean = obj1.headOption == obj2.headOption

val myList = List("aa", "bb", "cc", "a", "b", "c", "d")

myList.foldLeft(List[String]()) {
  case (accum, el) => if (accum.exists(verifySimilitude(el, _))) accum else el :: accum
}.reverse

Result:

res0: List[String] = List(aa, bb, cc, d)

Alternative (more efficient) solution would be to create wrapper class that implements equals and hashCode according to your verifySimilitude behavior. Reusing the example above, this will look like:

class SimWrapper(val v:String) {
  override def equals(other: Any): Boolean = other match {
    case that: SimWrapper => that.v.headOption == v.headOption
    case _ => false
  }

  override def hashCode(): Int = v.headOption.hashCode()
}

myList.map(new SimWrapper(_)).distinct.map(_.v)

With the same result:

res1: List[String] = List(aa, bb, cc, d)

Second approach is more efficient (O(N) comparing to O(N2)), but it also has limited applications, as it makes sense only when you can define reasonably uniform hashCode for particular verifySimilitude.

Upvotes: 4

Related Questions