Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy : how to group map values by 2 different criteria?

How can I group map values by 2 different criteria to get the outputs 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'],
]
  1. 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   
    
  2. 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 the way to iterate to effectively loop through the group structure, and be able to construct the result (group / subgroup / name ).

Something like :

  1. for each group, print/output the group name;
  2. for each subgroup inside a group, print/output the subgroup name
  3. inside each subgroup, print the names.

It would yield the result outlined above.

As a nice aside, I would like to sort the whole data structure (groups and names).

like image 820
Michel Parmentier Avatar asked Jan 26 '12 18:01

Michel Parmentier


1 Answers

For the first case:

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

and for the second:

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

You will end up with the original values in the map rather than just the name, but you will be able to do:

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

to get the result

["Ali", "Liu"]

btw: This form of groupBy has only been available since Groovy 1.8.1, so if you're stuck on an earlier version, this won't work

edit 2

Based on your comment below, you can then do:

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

This is the same logic as GVdP had in his answer, but I feel using the groupBy with multiple parameters like I have here makes your code more readable and obvious as to its intent

like image 77
tim_yates Avatar answered Oct 21 '22 03:10

tim_yates