BZapper
BZapper

Reputation: 330

Scala - diff two list of case classes by subset of fields

Given two lists of case classes

case class Entity(field1: String, field2: String, field3: String)
val a: Seq[Entity] = ...
val b: Seq[Entity] = ...

How to find all entities in a that's not in b, based on only field1 and field2, ignoring field3?

I've considered overriding the equals() function for the case class, also the neat trick of case class ()(ignored fields goes here) approach, but there will need to be multiple combinations of these fields needed for different use cases, e.g. diff using field1 + field2, then using field 1 + field 3, etc...

Upvotes: 6

Views: 2624

Answers (4)

Bob Dalgleish
Bob Dalgleish

Reputation: 8227

Create an entity mapping class that is only interested in fields you want to do the comparison on:

class EntityMap1_2( e: Entity ) {
  override def equals( o: Any ): Boolean = ???
  override def hashCode: Int = ???
}

It defines equals and hashCode only in terms of fields 1 and 2. Then you can populate respective sets and find the differences.

Similarly with other combinations of fields.

Upvotes: 0

Leo C
Leo C

Reputation: 22449

You can filter a with specific condition using !b.exists():

case class Entity(field1: String, field2: String, field3: String)
val a = Seq(Entity("1", "p", "x"), Entity("2", "q", "y"), Entity("3", "r", "z"))
val b = Seq(Entity("1", "p", "x"), Entity("2", "q", "x"), Entity("3", "s", "z"))

a.filter( elA => 
  !b.exists(elB => elB.field1 == elA.field1 && elB.field2 == elA.field2)
)
// res1: Seq[Entity] = List(Entity(3,r,z))

Upvotes: 2

user unknown
user unknown

Reputation: 36229

With ints, instead of String, for easy testing:

def similar (e: Entity, f: Entity) = { e.field1 == f.field1 && e.field2 == f.field2 }

scala> a
res60: Seq[Entity] = List(Entity(1,2,3), Entity(1,3,4), Entity(4,6,8), Entity(3,4,5))

scala> b
res61: Seq[Entity] = List(Entity(1,3,5), Entity(4,6,8), Entity(4,9,25))

scala> a.filter (aa => {! b.exists {bb => similar (aa, bb)} })
res62: Seq[Entity] = List(Entity(1,2,3), Entity(3,4,5))

Upvotes: 5

Dima
Dima

Reputation: 40500

  val bad = b.iterator.map { x => x.field1 -> x.field2 }.toSet
  val filtered = a.filterNot { x => bad(x.field1 -> x.field2) }

Upvotes: 2

Related Questions