Multi criteria sorting of a list of objects with Guava Ordering

喜欢而已 提交于 2020-01-12 07:01:16

问题


I have a class WHICH CANNOT implement comparable, but needs to be sorted based on 2 fields. How can I achieve this with Guava?

Let's say the class is:

class X {
  String stringValue;
  java.util.Date dateValue;
} 

And I have a list of these:

List<X> lotsOfX;

I want to sort them based on the value field first and then based on dateValue descending within each 'group' of 'value' fields.

What I have been doing so far is:

List<X> sortedList = ImmutableList.copyOf(Ordering.natural().onResultOf(dateValueSortFunction).reverse().sortedCopy(lotsOfX));
sortedList = ImmutableList.copyOf(Ordering.natural().onResultOf(stringValueSortFunction).sortedCopy(sortedList));

The functions are defined as:

public class DateValueSortFunction<X> implements Function<X, Long> {

    @Override
      public Long apply(X input) {
        return input.getDateValue().getTime();  //returns millis time
      }
}

And:

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;
        }
}

Expected output in sortedList is:

Something   03/18/2013
Something   03/17/2013
Something else  03/20/2013
Something else  03/19/2013
....

My approach works but is obviously inefficient for traversing the list twice. Is there a better way of doing this?

I am using this in a GWT app. Implementing comparable is not an option.


回答1:


I suspect you want Ordering.compound. You could do it all in one statement, but I'd use:

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:


A less functional, but arguably cleaner, solution:

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 provides methods on Comparator to concisely specify chained comparators. Together with the newly-introduced List.sort, you can do:

lotsOfX.sort(
    Comparator.comparingInt(x -> stringValueSortFunction.apply(x.stringValue))
        .thenComparing(x -> x.dateValue, Comparator.reverseOrder()));

This mutates the list, of course -- make a copy first if you want to leave the original list unchanged, or wrap the comparator in an Ordering and use immutableSortedCopy if you want an immutable copy.



来源:https://stackoverflow.com/questions/15532880/multi-criteria-sorting-of-a-list-of-objects-with-guava-ordering

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!