groupBy
Aman Aggarwal blogged about a powerful method from the
java.util.Collection
class. The groupBy
method converts a collection into a Map
with the keys being returned by the closure passed to the method.Example:
def map = invoices.groupBy { it.invoiceDate.format("MM/yyyy") }
map.each { k, v ->
println "There are ${v.size()} invoices in ${k}"
}
Incidentally, the example above uses another cool function from
java.util.Date
: format
. The method takes a date pattern (from the specification of java.text.SimpleDateFormat
) and returns a String
.inject
While writing about
groupBy
, I thought I might as well talk about the inject()
method too. It is a method that is best explained with an example. If I want to add all the numbers from 1 until 10, i.e. 1 + 2 + 3 + 4 + ... + 10, I can do it in one line:
def sum = (1..10).inject(0) { a, b -> a += b }
0 is passed as the initial value. In each iteration, the value from the last iteration is passed as
a
while the current value is passed as b
. If we add a println statement, e.g.
def sum = (1..10).inject(0) { a, b ->
println "${a} + ${b} = ${a + b}"
a += b
}
The output will be:
0 + 1 = 1
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
10 + 5 = 15
15 + 6 = 21
21 + 7 = 28
28 + 8 = 36
36 + 9 = 45
45 + 10 = 55
Another typical example is to calculate the product of a range of numbers. For example, to calculate the product of 1 to 10 (the factorial of 10):
def product = (1..10).inject(1) { a, b -> a *= b }
The result is the expected 3628800 (= 10!).
4 comments:
I haven't see the use of groupBy. Pretty cool.
What tool are you using to highlight your code in your blog?
jlorenzen: I'm using Alex Gorbatchev's Syntaxhighlighter 2.0. Check it out at http://alexgorbatchev.com
Note you can also get the sum of a colletion more clearly like this:
def sum = (1..10).sum { it }
An other example with groupBy, inject() and format() :
[sourcecode language='groovy']// Count the number of items and display them for each creator of more than 2 posts in RSS feeds
Locale.setDefault Locale.ENGLISH // if your computer doesn'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' (i.e. list of maps) with inject()
rssTable = rssXML.channel.item.inject([]) { allItems, eachItem ->
allItems << eachItem.children().inject([:]) { record, element ->
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})"
}
}[/sourcecode]
Post a Comment