Множество критериев сортировки списка объектов с помощью Guava Ordering
У меня есть класс, который не может реализовать сопоставимый, но должен быть отсортирован на основе 2 полей. Как я могу достичь этого с Guava?
Скажем, класс:
class X {
String stringValue;
java.util.Date dateValue;
}
И у меня есть список этих:
List<X> lotsOfX;
Я хочу отсортировать их сначала по полю значения, а затем по убыванию dateValue в каждой "группе" полей "значения".
Что я делал до сих пор:
List<X> sortedList = ImmutableList.copyOf(Ordering.natural().onResultOf(dateValueSortFunction).reverse().sortedCopy(lotsOfX));
sortedList = ImmutableList.copyOf(Ordering.natural().onResultOf(stringValueSortFunction).sortedCopy(sortedList));
Функции определены как:
public class DateValueSortFunction<X> implements Function<X, Long> {
@Override
public Long apply(X input) {
return input.getDateValue().getTime(); //returns millis time
}
}
А также:
public class StringValueSortFunction<X> implements Function<X, Integer> {
@Override
public Integer apply(X input) {
if(input.getStringValue().equalsIgnoreCase("Something"))
return 0;
else if(input.getStringValue().equalsIgnoreCase("Something else"))
return 1;
else
return 2;
}
}
Ожидаемый результат в sortedList
:
Something 03/18/2013
Something 03/17/2013
Something else 03/20/2013
Something else 03/19/2013
....
Мой подход работает, но, очевидно, неэффективен для обхода списка дважды. Есть ли лучший способ сделать это?
Я использую это в приложении GWT. Реализация сопоставимых не вариант.
Ответы
Ответ 1
Я подозреваю, что вы хотите Ordering.compound
. Вы можете сделать все это в одном заявлении, но я бы использовал:
Ordering<X> primary = Ordering.natural().onResultOf(stringValueSortFunction);
Ordering<X> secondary = Ordering.natural()
.onResultOf(dateValueSortFunction)
.reverse();
Ordering<X> compound = primary.compound(secondary);
List<X> sortedList = compound.immutableSortedCopy(lotsOfX);
Ответ 2
Менее функциональное, но, возможно, более чистое решение:
new Ordering<X>() {
public int compare(X x1, X x2) {
return ComparisonChain.start()
.compare(x1.stringValue, x2.stringValue)
.compare(x2.dateValue, x1.dateValue) // flipped for reverse order
.result();
}
}.immutableSortedCopy(listOfXs);
Ответ 3
Java 8 предоставляет методы для компаратора для краткого описания цепных компараторов. Вместе с недавно представленным List.sort вы можете:
lotsOfX.sort(
Comparator.comparingInt(x -> stringValueSortFunction.apply(x.stringValue))
.thenComparing(x -> x.dateValue, Comparator.reverseOrder()));
Это, конечно, мутирует список - сначала сделайте копию, если вы хотите оставить исходный список без изменений или обернуть компаратор в Ordering и использовать immutableSortedCopy
, если вы хотите неизменную копию.