I have two classes A
and B
. Both of them have the same property: id
and many other different properties.
How can I subtract Seq[A]
from Seq[B]
by matching the id
's?
I have two classes A
and B
. Both of them have the same property: id
and many other different properties.
How can I subtract Seq[A]
from Seq[B]
by matching the id
's?
This should work as long as the id field of both classes have the same type.
val as: Seq[A] = ???
val bs: Seq[B] = ???
val asSet = as.iterator.map(a => a.id).toSet
val substracted: Seq[B] = bs.filterNot(b => asSet(b.id))
Another feasible solution:
val seqSub = seqB.filterNot(x => seqA.exists(_.id == x.id))
Couldn't find an answer matching my definition of subtract, where duplicate elements aren't filtered, (e.g. Seq(1,2,2) subtract Seq(2) = Seq(1,2), det0's definition gives Seq(1) so posting it here.
trait IntId {
def id: Int
}
case class A(id: Int) extends IntId
case class B(id: Int) extends IntId
val seqB = Seq(B(1),B(4),B(7),B(7),B(7))
val seqA = Seq(A(7))
// BSubtractA = Seq(B(1),B(4),B(7),B(7)), only remove one instance of id 7
val BSubtractA = seqA.foldLeft(seqB){
case (seqBAccumulated, a) =>
val indexOfA = seqBAccumulated.map(_.id).indexOf(a.id)
if(indexOfA >= 0) {
seqBAccumulated.take(indexOfA) ++ seqBAccumulated.drop(indexOfA + 1)
}
else {
seqBAccumulated
}
}
Yes, there are shortcomings to this solution. For example, if seqA
is larger than seqB
, then it runs into null pointers (+ I haven't refactored it into a def). Also the performance could be improved to iterate fewer times over the input, however, this satisfied my use case.
That will be far more clean -
val seqSub = seqB.filterNot(x => seqA.contains(x))