removeAll function removes more than expected

33 views Asked by At

I have the following functionality that I’ve seen people use in order to get the differences between two lists.

Note: this is not the actual code but a representation of what I have, in actuality each number can be replaced by an object with properties.

def listA = [1,2,3,4,5]
def listB = [1,2,3,6,7]

def common = listA.intersect(listB)//expected: [1,2,3], actual: same
def all = listA.plus(listB)//expected: [1,1,2,2,3,3,4,5,6,7], actual: same
all.removeAll(common)//expected: [4,5,6,7], actual: [6,7]
2

There are 2 answers

0
Amadan On

Simplified,

def big = [1, 1, 2, 3]
def small = [1, 2]

The code

big.removeAll(small)

removes all matching elements. Both 1 and 1 from big match 1 from small, so they are both removed, for the result [3]. What you probably want is

small.each { big.removeElement(it) }

where for each element of small a single matching element of big is removed, for the result [1, 3].

See docs.

0
cfrick On

You want the Symmetric difference between your two sets.

Groovy 5 will have the ^ operator(-overload) for this:

var a = [1, 2, 3] as Set 
var b = [2, 3, 4] as Set
assert (a ^ b) == [1, 4] as Set

But you can do this now now manually, by removing the intersection from the union.

def listA = [1,2,3,4,5].toSet()
def listB = [1,2,3,6,7].toSet()

def union = listA + listB
def intersection = listA.intersect(listB)

def symmetricDifference = union - intersection

println(symmetricDifference) // → [4, 5, 6, 7]