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:

  1. 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!

    ReplyDelete
  2. 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 }

    ReplyDelete
  3. Very helpful indeed - thanks for posting!

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

    thanks again buddy

    - Sturtz

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

    ReplyDelete
  6. I looked for this for 2 days!!

    Thanks

    ReplyDelete
  7. 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?"

    ReplyDelete
  8. 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

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

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

    ReplyDelete
  11. 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

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

    ReplyDelete
  13. To sort a list of map entries, use either:

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

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

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

    ReplyDelete
  16. 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()

    ReplyDelete
  17. 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 ?

    ReplyDelete
  18. 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"]

    ReplyDelete
  19. Thank you , it is still helping us.

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

    ReplyDelete
  21. Thank you very much. This really helped a lot.

    ReplyDelete
  22. 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.

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

    ReplyDelete
  24. 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

    ReplyDelete
  25. to Sonu

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

    ReplyDelete
  26. Incredibly helpful. Thank you so much.

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

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

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

    ReplyDelete
  29. 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()}

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

    ReplyDelete
  31. 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)

    ReplyDelete
  32. WOW, that was simple, thanks!

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

    ReplyDelete