How to sort a list by existing properties

I use this line here to sort the list based on the name of the object.

gVsort{it.name} 

How do I sort it based on "name", if it exists, if not, I want to sort it by "title". If both exist, I want to sort them first by name and then by name.

I am not a Groovy encoder, so thanks for the help in advance.

+8
java sorting groovy
source share
3 answers

I'm not sure I understand your question correctly. Perhaps something like this is what you are looking for:

 def things = [ [name: 'aaa', title: '222'], [name: 'aaa', title: '333'], [title: '222'], [title: '111'], [name: 'bbb', title: '111'], [title: '333'], [name: 'aaa', title: '111'], ] things.sort { a, b -> // Compare by name and then by title. a.name <=> b.name ?: a.title <=> b.title } assert things == [ [title: '111'], [title: '222'], [title: '333'], [name: 'aaa', title: '111'], [name: 'aaa', title: '222'], [name: 'aaa', title: '333'], [name: 'bbb', title: '111'], ] 

What happens inside this seemingly innocent comparison function is actually quite a bit of Groovy syntax magic. But it is not too difficult.

First, the sort method is called using a binary function that acts as a comparator (i.e., it takes two arguments: a and b and returns -1 if a <b, 1 if a> b and 0 if a = = b).

This anonymous function: { a, b -> a.name <=> b.name ?: a.title <=> b.title } uses the spacecraft operator "( <=> ... that man is a spaceship!) before first compare a and b by name.

If the names are equal (or both are equal to zero), then the result a.name <=> b.name is 0, which is falsely calculated in the Elvis operator "( ?: ... imagine it as an emoticon), so the result is a.title <=> b.title .

Otherwise, if the result of the comparison of names is not equal to 0, then this is fairly evaluated in the Elvis operator and this value is returned.

This is all, given that you can compare null values ​​with strings and that 'any string' > null always executed (this is the same as saying that 'any string' <=> null == 1 ).

So, the end result is that elements without a name are first sorted by title, and then elements with a name and a name are sorted first by name and then by name.

Hope this was what you were looking for. If you were expecting a different order of sorted items, feel free to clarify it in the comments :)

Update

There is also an undocumented OrderBy object that can be used in this case:

 things.sort new OrderBy([{it.name}, {it.title}]) 
+13
source share

You can sort the collection using Comparator .

 gVsort { a, b -> a.name <=> b.name ?: a.title <=> b.title } 
+4
source share

This is my completely untested effort, which is probably riddled with errors

 def comparator = {o1, o2 -> // wording of question suggests title will always exist, if not, add more hasProperty checks def diff = o1.title <=> o2.title if (o1.hasProperty('name') && o2.hasProperty('name')) { def nameDiff = o1.name <=> o2.name if (nameDiff != 0) { diff = nameDiff } } diff } as Comparator def someList = [] // populate the list... someList.sort(comparator) 
0
source share

All Articles