Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy: map reduce list of maps

Assuming I have list of maps in Groovy:

def listOfMaps = [
[k: 1, n: 'Name1', d1: 'a', d2: 'b'],
[k: 2, n: 'Name2', d1: 'c', d2: 'd'],
[k: 1, n: 'Name3', d1: 'e', d2: 'f'],
[k: 4, n: 'Name4', d1: 'g', d2: 'h']]

I need to find if there exist (or not) items, where k is equal, but n is not. E.g. in this case we have two map records with "k" = 1 and "n" is 'Name1' and 'Name3'. How can I find such data? I suppose I should group by "k" and count distinct values in "n", if there are more than 1 unique values in "n" for certain "k" - we found such data. I'm completely stuck so any help will be appreciated. Thanks

like image 398
lospejos Avatar asked Aug 28 '15 14:08

lospejos


People also ask

How do I iterate a map in groovy?

If you wanted to do it that way, iterate over map. keySet() and the rest will work as you expected. It should work if you use s. key & s.

Are Groovy maps ordered?

Maps don't have an order for the elements, but we may want to sort the entries in the map. Since Groovy 1.7. 2 we can use the sort() method which uses the natural ordering of the keys to sort the entries. Or we can pass a Comparator to the sort() method to define our own sorting algorithm for the keys.

How do I use Groovy maps?

Maps are generally used for storing key-value pairs in programming languages. You have two options to declare a map in groovy. First option is, define an empty map and put key-value pairs after. Second option is declaring map with default values.

How do I add a map to Groovy?

2. Creating Groovy Maps. We can use the map literal syntax [k:v] for creating maps. Basically, it allows us to instantiate a map and define entries in one line.


2 Answers

EDIT

Now I've worked out what you meant, here's the code:

listOfMaps.groupBy { 
   it.k }.
values().
findAll { l -> 
   l.size() > 1 && (l.size() == l.unique { e -> e.n }.size()) 
}

At the beginning the list is grouped by k element, then among the values we search for lists with size higher than 1 and which size is equal to count of unique n elements. It works correctly.

OLD ANSWERS

You can try the combination of findAll and unique:

def listOfMaps = [
    [k: 1, n: 'Name1', d1: 'a', d2: 'b'],
    [k: 2, n: 'Name2', d1: 'c', d2: 'd'],
    [k: 1, n: 'Name3', d1: 'e', d2: 'f'],
    [k: 4, n: 'Name4', d1: 'g', d2: 'h'],
]

listOfMaps.findAll { it.k == 1 }.unique { it.n }

Or with groupBy:

listOfMaps.groupBy { it.k }[1].unique { it.n }

In groovy there are many ways of doing it ;)

like image 63
Opal Avatar answered Sep 22 '22 21:09

Opal


If you are interested in a reducing version, this one builds a map of k to a set of ns.

def r = listOfMaps.inject([:].withDefault{[].toSet()}) { m, it -> 
    m.get(it.k).add(it.n); m }
println r.findAll{ it.value.size()>1 }
// => [1:[Name3, Name1]]
like image 39
cfrick Avatar answered Sep 25 '22 21:09

cfrick