We want to sort objects by three different criteria, the criteria with higher priority overrides the next one):
- status field
- time field
- sort field
- status are enums and have a custom sorting, which we implemented by a comparator. (unknown, open, closed,)
- sortBy Field is an Integer and can be sorted accordingly
- time field can be null, we only want to sort the ones with null to the top and leave the remaining sorting as it is
example:
- Object1(status: open, time: 1, sort: 4)
- Object2(status: closed, time: null, sort: 1)
- Object3(status: unknown, time: 2, sort: 3)
- Object4(status: unknown, time: null, sort: 2)
- Object5(status: open, time: 1, sort: 5)
sorted:
- Object 3 (status: unknown)
- Object 4 (status: unknown, next item in the original list)
- Object 2 (status != unknown, time: null)
- Object 1 (status != unknown, time != null, sort: 4)
- Object 5 (status != unknown, time != null, sort: 5)
we return the list the following way:
list.sortedWith(statusComparator.thenBy { it.sort }
What is missing is the sorting of items with time = null. How do I sort the items with time = null to the top and leave the remaining sorting untouched?
CodePudding user response:
You can combine Comparator
objects with thenComparing
so you probably want to write a comparator for the time something like
val timeComparator = Comparator<YourObject> { first, second ->
when {
first.time == null && second.time != null -> -1
first.time == null && second.time == null -> 0
first.time != null && second.time == null -> 1
else -> 0
}
}
And then change
list.sortedWith(statusComparator.thenBy { it.sort }
to
list.sortedWith(statusComparator.thenComparing(timeComparator).thenBy { it.sort })
CodePudding user response:
To sort depending if the value is null we can... do exactly this, sort by checking if it is null:
list.sortedWith(
statusComparator
.thenBy { it.time != null }
.thenBy { it.sort }
)
It works, because false
is considered smaller than true
. And it returns true
for any non-null value, so all non-null values are considered the same.
We can join time
and sort
steps into a single one, by returning null if time
is null and sort
otherwise:
.thenBy { item -> item.time?.let { item.sort } }
// or:
.thenBy { if (it.time == null) null else it.sort }
It could be a little more performant, but I consider this harder to understand and less flexible.