Groovy: how to group map values ​​according to two different criteria?

How can I group map values ​​according to two different criteria to get the results below?

def listOfMaps = [ [name:'Clark', city:'London', hobby: 'chess'], [name:'Sharma', city:'London', hobby: 'design'], [name:'Maradona', city:'LA', hobby: 'poker'], [name:'Zhang', city:'HK', hobby: 'chess'], [name:'Ali', city: 'HK', hobby: 'poker'], [name:'Liu', city:'HK', hobby: 'poker'], [name:'Doe', city:'LA', hobby: 'design'], [name:'Smith', city:'London', hobby: 'poker'], [name:'Johnson', city: 'London', hobby: 'poker'], [name:'Waters', city:'LA', hobby: 'poker'], [name:'Hammond', city:'LA', hobby: 'design'], [name:'Rogers', city:'LA', hobby: 'chess'], ] 
  • Group order: hobby, city

     poker London Smith Johnson LA Maradona Waters HK Ali Liu design London Sharma LA Doe Hammond HK chess London Clark LA Rogers HK Zhang 
  • Group order: city, hobby

     London poker Smith Johnson design Sharma chess Clark LA poker Maradona Waters design Doe Hammond chess Rogers HK poker Ali Liu design chess Zhang 

Edit:

What I really need is an iteration method to efficiently loop through the group structure and the ability to build the result (group / subgroup / name).

Sort of:

  • for each group, print / print the name of the group;
  • for each subgroup within the group, type / print the name of the subgroup
  • inside each subgroup, type the names.

This will give the result described above.

As well, I would like to sort the entire data structure (groups and names).

+6
source share
3 answers

In the first case:

 result = map.groupBy( { it.hobby }, { it.city } ) 

and for the second:

 result = map.groupBy( { it.city }, { it.hobby } ) 

As a result, you will get the original values ​​on the map, not only the name, but you can:

 result[ 'poker' ][ 'HK' ].name 

to get the result

 ["Ali", "Liu"] 

btw: This form of groupBy is only available with Groovy 1.8.1, so if you are stuck with an earlier version, this will not work

change 2

Based on your comment below you can:

 result.each { a, b -> println "$a" b.each { c, d -> println " $c" d.each { println " $it.name" } } } 

This is the same logic as GVdP in his answer, but I feel that with groupBy with several parameters, like mine, here your code becomes more readable and obvious regarding its intent

+15
source

If you want to have multiple nested maps as a result, try something like this:

 def byHobbyCity = map.groupBy{it.hobby}.collectEntries{k, v -> [k, v.groupBy{it.city}]} def byCityHobby = map.groupBy{it.city}.collectEntries{k, v -> [k, v.groupBy{it.hobby}]} println byHobbyCity['chess']['London']*.name ==> [Clark] println byCityHobby['London']['chess']*.name ==> [Clark] 
+2
source

Responding to your comments, this will do as you ask:

 def listOfMaps = [ [name:'Clark', city:'London', hobby: 'chess'], [name:'Sharma', city:'London', hobby: 'design'], [name:'Maradona', city:'LA', hobby: 'poker'], [name:'Zhang', city:'HK', hobby: 'chess'], [name:'Ali', city: 'HK', hobby: 'poker'], [name:'Liu', city:'HK', hobby: 'poker'], [name:'Doe', city:'LA', hobby: 'design'], [name:'Smith', city:'London', hobby: 'poker'], [name:'Johnson', city: 'London', hobby: 'poker'], [name:'Waters', city:'LA', hobby: 'poker'], [name:'Hammond', city:'LA', hobby: 'design'], [name:'Rogers', city:'LA', hobby: 'chess'], ] listOfMaps.groupBy {it.hobby}.each { k,v -> println k v.groupBy {it.city}.each {k1, v1-> println " $k1" v1.each { println " $it.name" } } } 

Tested with Groovy 1.7.10

+1
source

Source: https://habr.com/ru/post/906970/


All Articles