Hi folks,
I was recently looking at some of the functionality offered by Eclipse
Collections. One nice feature is its groupByEach method. It simplifies
using collectMany then groupBy.
To fit in with Groovy naming, I think groupByMany is slightly better
in Groovy's case but the examples below show how current functionality
works (using collectMany/groupBy and then using groovy-ginq) and then
how be done using groupByMany:
def citiesLived = [
Alice: ['NY', 'LA'],
Bob: ['NY'],
Cara: ['LA', 'CHI']
]
We want the reverse map of cities -> list of names:
def grouped1 = citiesLived
.collectMany(e -> e.value.collect{ c -> [c, e.key] })
.groupBy{ c, n -> c }
.collectEntries{ key, value -> [key, value*.get(1)] }
check(grouped1)
Alternatively, we can use groovy-ginq:
def grouped2 = GQL {
from n in citiesLived.keySet()
crossjoin c in citiesLived.values().sum().toSet()
where c in citiesLived[n]
groupby c
select c, list(n)
}
check(grouped2.collectEntries())
Here is what it looks like with the proposed method:
def grouped3 = citiesLived.keySet().groupByMany { n -> citiesLived[n] }
check(grouped3)
def check(grouped) {
assert grouped == [
NY : ['Alice', 'Bob'],
LA : ['Alice', 'Cara'],
CHI : ['Cara']
]
}
This is particularly useful for Eclipse Collections multimaps but maps
with lists are common enough in Groovy even without explicit multimaps
that I think this is valuable. You can think of it a little like the
"inverse" method of a BiMap implementation but instead of inverting K
and V we swap between K, List<V> to V, List<K>.
Thoughts? I'll create a PR unless folks don't feel it adds enough
value or want to comment on the proposed functionality and naming.
Cheers, Paul.