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
You can sorts the Collection using a Comparator
.
g.V.sort { a, b ->
a.name <=> b.name ?: a.title <=> b.title
}
This is my totally untested effort which is probably riddled with bugs
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)
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 :)
There is also a not very documented OrderBy object that can be used in this case:
things.sort new OrderBy([{it.name}, {it.title}])