Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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...

like image 800
BZapper Avatar asked Feb 06 '18 20:02

BZapper


3 Answers

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))
like image 95
user unknown Avatar answered Oct 27 '22 10:10

user unknown


  val bad = b.iterator.map { x => x.field1 -> x.field2 }.toSet
  val filtered = a.filterNot { x => bad(x.field1 -> x.field2) }
like image 2
Dima Avatar answered Oct 27 '22 09:10

Dima


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))
like image 2
Leo C Avatar answered Oct 27 '22 09:10

Leo C