Firstly let's explain how GroovyCollections.transpose(List lists)
works to solve this problem. For given output
def x = [ [a:1, b:2], [a:1, b:3], [a:2, b:4], [a:3, b:5] ]
def y = [ [f:10, b:2, g:7], [f:100, b:3, g:8], [f:20, b:4, g:9], [f:20, b:6, g:9] ]
expression
[x,y].transpose()
creates a list of pairs:
[
[[a:1, b:2], [f:10, b:2, g:7]],
[[a:1, b:3], [f:100, b:3, g:8]],
[[a:2, b:4], [f:20, b:4, g:9]],
[[a:3, b:5], [f:20, b:6, g:9]]
]
If we compare it with a list you expect to get
def expected = [[a:1, b:2, f:10, g:7], [a:1, b:3, f:100, g:8], [a:2, b:4, f:20, g:9], [a:3, b:5], [a:3, b:6, f:20, g:9]]
we can see that it contains not 4, but 5 elements. There is one hidden requirement that can be found after investigating desired result: if there is a pair of two maps that has at least one common key, but with two different values for each pair element, then don't merge those two pairs, but create two maps instead, where first map is a map that comes from x
and is unchanged and second one is a result of merging maps from x
and y
.
How to check if two maps have at least one common key with different values?
We can use Collection.intersect(Collection right)
for that. But we have to compare two intersections:
- Intersection of
Map.keySet()
keys
- Intersection of
Map.Entry
elements from both maps
First intersection will tell us if there are same keys in both maps, while the second intersection will tell us if they store the same value. If both expressions evaluate to true
, we will merge them with a + b
as it was in the example you have mentioned (we will also use the same method if both maps does not have any keys in common). But if both maps have non-empty intersection of keys while intersection of map entries is not equal to the result of first intersection we will merge these maps using [a, a+b]
and we will .flatten()
the result eventually. Below you can find a Groovy code that does what I have just described:
def x = [[a: 1, b: 2], [a: 1, b: 3], [a: 2, b: 4], [a: 3, b: 5]]
def y = [[f: 10, b: 2, g: 7], [f: 100, b: 3, g: 8], [f: 20, b: 4, g: 9], [f: 20, b: 6, g: 9]]
def expected = [[a: 1, b: 2, f: 10, g: 7], [a: 1, b: 3, f: 100, g: 8], [a: 2, b: 4, f: 20, g: 9], [a: 3, b: 5], [a: 3, b: 6, f: 20, g: 9]]
def shareSameKeyWithSameValue(Map<String, ?> a, Map<String, ?> b) {
final Set<String> keysIntersectionFromEntries = (a.entrySet().intersect(b.entrySet())).key as Set
final Set<String> keysIntersection = a.keySet().intersect(b.keySet())
return !keysIntersectionFromEntries.isEmpty() && keysIntersectionFromEntries.containsAll(keysIntersection)
}
def result = [x, y].transpose().collect { a, b ->
shareSameKeyWithSameValue(a, b) ? a + b : [a, a + b]
}.flatten()
assert result == expected
I hope it helps.