Saturday, May 17, 2008

Groovy Sort List

I am posting a simple example on how to sort a list in groovy because the examples google knows about aren't what I was looking for. With some deep digging I was able to find a clue that eventually solved my problem.

It's real easy to sort a list of numbers

assert [1,2,3,4] == [3,4,2,1].sort()

Or even strings

assert ['Chad','James','Travis'] == ['James','Travis','Chad'].sort()

But this was my example

class Person {
String id
String name
}
def list = [new Person(id: '1', name: 'James'),new Person(id: '2', name: 'Travis'), new Person(id: '3', name: 'Chad')]

list.sort() returns James, Travis, Chad

The solution is ridiculously simple (not that I thought the previous sort would work; I have to be realistic; groovy can't do everything for me).

list.sort{it.name} will produce an order of Chad, James, Travis.

In the previous example note the use of the sort closure sort {} verses the sort() method.

Now I am not sure, off the top of my head and without a Groovy book handy, the simplest way to sort case insensitive.

assert ['a1','A1'] == ['A1,'a1'].sort{fancy closure}

39 comments:

Anonymous said...

You sir, are my friggin' hero. I've been messing with trying to create my own tag, etc for this, and you have the answer!

Thank you 10 times over!

Anonymous said...

Your post really helped me, James.

I found myself wanting case-insensitive sorting, too, so here's what worked for me (I tweaked your test data to make it more obvious):

assert ['a1', 'A2', 'a3'] == ['A2','a3', 'a1'].sort { a, b -> a.compareToIgnoreCase b }

Richard Berger said...

Very helpful indeed - thanks for posting!

Chad Sturtz said...

To no surprise, your post showed up in my google search for groovy list sorting ...

thanks again buddy

- Sturtz

sheriffbills said...

Thank you very much :-)

Anonymous said...

GREAT! Thank you!

Anonymous said...

Wouldn't a better solution be to implement Comparable and override compareTo method?

Anonymous said...

thx bro :)

Joshery said...

I looked for this for 2 days!!

Thanks

Anonymous said...

Good post indeed, but in most cases I think the Anonymous poster from March 1, 2009 9:44 PM had the better solution as it's more reusable.

"Wouldn't a better solution be to implement Comparable and override compareTo method?"

justin_loh said...

This is my solution:

class Person {
String id
String name
}

def list = [new Person(id: '1', name: 'James'),new Person(id: '2', name: 'Travis'), new Person(id: '3', name: 'Chad'),
new Person(id:'4', name:'angel')]

println list.name

// If you want to sort with Case sensitive, uncomment sort with spaceship operator <==> and comment the sort with compareToIgnoreCase
// list.sort { p1, p2 -> p1.name <=> p2.name }

list.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }

println list.name

Michael Easter said...

thanks for posting! It helped me just now and I bet it has helped far more than those who took the time to comment.

Blundell said...

Yeah but, what if you wanted to reverse the sort order?

duxx0r said...

Much appreciated dude!!

Henrik said...

To reverse sort order just add a dash before it. I just tried this (but for numeric values) and it worked.

list.sort{-it.name}

//Henrik Sjostrand

Ewan said...

Nice, just what I was looking for. Thanks James.

Rob Stoecklein said...

To sort a list of map entries, use either:

list.sort{it.key}
or
list.sort{it.value}

retnyc.ubando said...

Thanks for the great job.Can you give us an exmple of how do we apply this on GSPs?

retnyc.ubando said...

Great Job there. Can you give also show us how we can apply this to our table listing on GSPs?

Mattias Jonsson said...

Fantastic, many thanks.

/Mattias

Dem_Stillers said...

This post helped me greatly. Thanks. For reverse order I found that you need to add .reverse() to ones sort closure.

e.g.
myList.sort{ it.date}.reverse()

Anonymous said...

Is there any way to specify the order like in mysql we can specify "order by field(id, 2,3,1,4)". Can we specify such order on a property of domain class in grails criteria ?

Anonymous said...

To sort case sensitive:

assert ["b","A","C","d"].sort() == ["A","C","b","d"]

To sort case insensitive:

assert ["b","A","C","d"].sort{it.toLowerCase()} == ["A","b","C","d"]

timo said...

thanks alot!

Mohana said...

Thank you , it is still helping us.

Anonymous said...

Amazing... I find more and more answers to my questions on your blog. Big fan already. Thanks a bunch.

Anonymous said...

Thank you very much. This really helped a lot.

Rob Man said...

Anon in Feb asked about sorting with multiple db fields.
I just did this, here's my solution. Elegance upgrades welcome!

things.sort {thing1, thing2-> (thing1.field1<=>thing2.field1)?:(thing1.field2<=>thing2.field2)}

Love the terminology ... "Elvis and the spaceships"

Note, I actually wanted to reverse order the second field, so I negated the second sort:

things.sort {thing1, thing2-> (thing1.field1<=>thing2.field1)?:-(thing1.field2<=>thing2.field2)}

This is for two db fields ... multiple? does the structure hold up? for you to try if you want.

Anonymous said...

this blog even helped me...thanks a ton...

Sonu said...

HOw to sort this array value??
data = [[1,23],[1,13],[2,543],[2,573]]
I want to sort on the basis of second value of array like
[[1,13],[1,23],[2,543],[2,573]]

Thanks

Юрк said...

to Sonu

[[1,23],[1,13],[2,543],[2,573]].sort {a, b -> a[1].compareTo(b[1])}

Anonymous said...

Incredibly helpful. Thank you so much.

Anonymous said...

If you want case insensitive searching but also protection from nulls, try:

.sort {it.name?.toLowerCase()}

Unknown said...

This continues to be very valuable information. Thanks for posting it.

Unknown said...

Five years later, James's post is still the best thing on the web for Groovy newcomers, like me.

After I used this to get my sorting done, I tried it again, but made the very mistake that the original post had warned about--using parentheses instead of curly braces (sorry, James, I need to read more slowly).

Watch out for this mistake -- it produces mysterious error messages, such as "Cannot get property 'name' on null object" or "No such property: it for class".

This experience prodded me into figuring out what the curly-brace syntax was actually doing

(see http://groovy.codehaus.org/groovy-jdk/java/util/Collection.html#sort(java.util.Comparator) )

which in turn suggests what I believe is the simplest solution to case-insensitive sorting (at least it worked for me):

list.sort {it.name.toLowerCase()}

Unknown said...

Oops! I now see that Anonymous beat me to that case-insensitive solution by about five months -- and with more robust code too.

Unknown said...

Oops again. The documentation link I posted should have been to the overloading of sort() that uses a closure:

http://groovy.codehaus.org/groovy-jdk/java/util/Collection.html#sort(groovy.lang.Closure)

Anonymous said...

WOW, that was simple, thanks!

Anonymous said...

you just saved me a bunch of extra work. thank you