Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort a list by existing properties

I am using this line here to sort a list based on the object's name.

g.V.sort{it.name}

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

I'm not a Groovy coder so thanks for the help in advance.

like image 498
ajsie Avatar asked Mar 04 '12 22:03

ajsie


People also ask

How do you sort a list containing objects?

sort() method to sort a list of objects using some examples. By default, the sort() method sorts a given list into ascending order (or natural order). We can use Collections. reverseOrder() method, which returns a Comparator, for reverse sorting.

How do you sort a list of objects based on an attribute of the objects in Java 8?

Java 8 introduced a sort method in the List interface which can use a comparator. The Comparator. comparing() method accepts a method reference which serves as the basis of the comparison. So we pass User::getCreatedOn to sort by the createdOn field.


2 Answers

I'm not sure I understand your question correctly. Maybe 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's happening inside that seemingly innocent comparison function is actually quite a lot of Groovy syntax magic. But it's not too difficult to follow.

First, the sort method is being invoked with a binary function that acts as a comparator (i.e. 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 "spaceship operator" (<=>... that's a spaceship man!) to first compare a and b by names.

If the names are equal (or both null), then the result of a.name <=> b.name is 0, which evaluates falsely in the "Elvis operator" (?:... imagine it as a smiley), so then the result of a.title <=> b.title is returned.

Otherwise, if the result of the name comparison is not 0, then that evaluates truthfully in the Elvis operator and that value is returned.

This is all taking into consideration that you can compare null values with strings and that 'any string' > null always holds (which is the same as saying that 'any string' <=> null == 1).

So the final result is that elements with no name are first and sorted by title, and then the elements with name and title are ordered first by name and then by title.

I hope that was what you were looking for. If you were expecting a different ordering of the sorted elements feel free to clarify it in the comments :)

Update

There is also a not very documented OrderBy object that can be used in this case:

things.sort new OrderBy([{it.name}, {it.title}])
like image 135
epidemian Avatar answered Oct 02 '22 15:10

epidemian


You can sorts the Collection using a Comparator.

g.V.sort { a, b ->
    a.name <=> b.name ?: a.title <=> b.title
}
like image 43
Arturo Herrero Avatar answered Oct 02 '22 14:10

Arturo Herrero