Grouping Items in a Collection

To group items in a collection, use the groupBy() function, providing a closure to evaluate as the grouping key.

For example, given a list of words you can group them based on the length of each word by doing the following:

def words = ['For', 'example', 'given', 'a', 'list', 'of', 'words', 'you', 'can',
             'group', 'them', 'based', 'on', 'the', 'length', 'of', 'each', 'word']
def groupedByLength = words.groupBy{ it.length() } 
This produces the following result of type Map of List:
[ 
  3:['For', 'you', 'can', 'the'], 
  7:['example'], 
  5:['given', 'words', 'group', 'based'], 
  1:['a'], 
  4:['list', 'them', 'each', 'word'], 
  2:['of', 'on', 'of'], 
  6:['length']
]
To produce a count of the number of items in each group, use the countBy() function, passing the same kind of closure to determine the grouping key:
def countsByLength = words.countBy{ it.length() }

This produces a map with the word lengths as the map key and the count as the value:

[3:4, 7:1, 5:4, 1:1, 4:4, 2:3, 6:1]

You can group and sort any collection as needed. For example, after grouping and counting the list of words above, you can group the resulting map into further groups based on whether the words have an even number of characters or an odd number of characters like this:

def evenOdd = countsByLength.groupBy{ it.key % 2 == 0 ? 'even' : 'odd' }
This produces a map of maps like this:
[odd:[3:4, 7:1, 5:4, 1:1], 
 even:[4:4, 2:3, 6:1]]
These functions can be chained so you can produce a sorted list of words containing less than three letters and the count of their occurrences by doing:
def shortWordCounts = words.findAll{ it.length() < 3 }
                           .countBy{ it }
                           .sort{ it.key }
The code is compact and easy to understand, but if you want to rename the closure parameters to make them even more self-documenting:
def shortWordCounts = 
    words.findAll{ word -> word.length() < 3 }
         .countBy{ word -> word 
         .sort{ wordCountMapEntry -> wordCountMapEntry.key }
For the final flourish, you could consider even adding additional comments like this:
def shortWordCounts = 
          // Find words less than 3 characters
    words.findAll{ word -> word.length() < 3 }
         // Then count how many times each resulting word occurs
         .countBy{ word -> word }
         // Then sort alphabetically by word
         .sort{ wordCountMapEntry -> wordCountMapEntry.key }
This produces the desired result of:
[a:1, of:2, on:1]