Groovy Collection method: groupBy()
public Map groupBy(Closure closure)
Going through Groovy Collection, I found this powerful method which takes a Closure as parameter & based on the closure, it returns a map in which all unique values returned by closure act as keys.
Lets take an example:
If you want to group integers between 1 to 100 based on the integer value at units place as follows:
[1:[1, 11, 21, 31, 41, 51, 61, 71, 81, 91],
2:[2, 12, 22, 32, 42, 52, 62, 72, 82, 92],
3:[3, 13, 23, 33, 43, 53, 63, 73, 83, 93],
4:[4, 14, 24, 34, 44, 54, 64, 74, 84, 94],
5:[5, 15, 25, 35, 45, 55, 65, 75, 85, 95],
6:[6, 16, 26, 36, 46, 56, 66, 76, 86, 96],
7:[7, 17, 27, 37, 47, 57, 67, 77, 87, 97],
8:[8, 18, 28, 38, 48, 58, 68, 78, 88, 98],
9:[9, 19, 29, 39, 49, 59, 69, 79, 89, 99],
0:[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]
Just think of the code you will need to write in Java for this.
However, its a single method call in Groovy: (1..100).groupBy{it%10}
Hope to find more such methods over time.
–
~Aman Aggarwal
aman@intelligrape.com
Thanks for the post. This helped me with an example to use groupby
Thanks for the tips!
Thanks for the tip! There are a lot of great methods added to Collection by Groovy.
I recently blogged about the min() and max() methods
For example, if you want to find the most recently modified file in a directory (dir), this is all you need:
def newestFile =
dir.listFiles().max{ it.lastModified() }
Maybe a more use case as requested above:
Map invoicesPerClient = invoices.groupBy{ it.client }
invoicesPerClient.each { client, invoices ->
println client.name + ” has ” + invoices.length + ” invoices”
}
// An other example of groupBy :
// Count the number of items and display them for each creator of more than 2 posts in RSS feeds
// Bernard Giusiano – 08/04/09
Locale.setDefault Locale.ENGLISH // if your computer don’t speak english
rssFeed = “http://feeds2.feedburner.com/groovyblogs”.toURL().text // my prefered Groovy RSS
rssXML = new XmlSlurper().parseText(rssFeed) // get data
// transform rssXML into a table (list of maps)
rssTable = rssXML.channel.item.inject([]) { allItems, eachItem ->
allItems <
record += [(element.name()):(element.toString())]
}
}
// group by creator
groupedByCreator = rssTable.groupBy { it.creator }
// select creators who have posted more than two times
moreThanTwo = groupedByCreator.findAll { group -> group.value.size() > 2 }
// display what you want from each group
moreThanTwo.each { group ->
println group.key.padRight(70,’.’) + group.value.size() + ‘ items’
group.value.each { post ->
println ” ${Date.parse(‘EEE, d MMM yyyy HH:mm:ss Z’,post.pubDate).format(‘dd/MM/yy’)} : ${post.title} (${post.link})”
}
}
return null // to stop display of big result in GroovyConsole
Is this a more realistic use case?
[ ‘Java’, ‘Groovy’, ‘JavaScript’, ‘Smalltalk’ ].groupBy { it[0] }
It sorts the languages by their first letter:
[J:[Java, JavaScript], G:[Groovy], S:[Smalltalk]]
really a powerful method. thanx 4 sharing such valuable info… it will be more helpful if u give more realistic use case to use such a method.