Amit Yadav
Amit Yadav

Reputation: 35034

Java Collections.sort() Comparator

I am sorting my custom objects. Custom object contain state and timestamp. First I have to sort against state then timestamp. State having below values

Running, Waiting, Registering, Completed and Aborted

So state having value Running should come on top then Waiting and so on.

If I have to sort alphabetically then I can do easily via

state1.compareTo(state2)

But can I sort with this criteria. Please help me to write this logic.

EDIT

As you people suggested I took Enum

private enum TournamentState {
    Running,
    Waiting,
    Registering,
    Completed,
    Aborted
}

And compare like below

int sort = EnumState.valueOf(status1).compareTo(EnumState.valueOf(status2));

if(sort != 0){
  return sort;
}else{
   return (int) (time1 - time2);
}

Thank you very much for your support.

Upvotes: 1

Views: 1488

Answers (3)

ernest_k
ernest_k

Reputation: 45309

You can use composition of comparator functions:

Comparator<MyClass> comparator = Comparator.comparing(MyClass::getState)
    .thenComparing(MyClass::getTimeStamp);

The last line may need to be changed accordingly, depending on the data type:

.thenComparingLong(MyClass::getTimeStamp); //if it's a long TS

Or even

.thenComparing((ts1, ts2) -> {
    //custom comparison logic for time stamp values
    return result;
 });

Comparator.thenComparing is documented with this comment:

Returns a lexicographic-order comparator with another comparator. If this Comparator considers two elements equal, i.e. compare(a, b) == 0, other is used to determine the order.

Note that MyClass.state is assumed to be comparable in this case, such as being an enum, which is inherently comparable. If it's plain strings, then you may need custom logic there too, such as with:

final String order = "Running, Waiting, Registering, Completed and Aborted";
Comparator<MyClass> comparator = 
  Comparator.comparingInt(e -> order.indexOf(e.getState()))
    .thenComparing(MyClass::getTimeStamp);

Upvotes: 4

Indent
Indent

Reputation: 4967

You can create a custom comparator for your State class, like this :

public final class StateComparator implements Comparator<State>
{

    private int getRank(final State s)
    {
        if (s.getValue().equals("Running"))
        {
            return 1;
        } else if (s.getValue().equals("Waiting")) {
            return 2;
        } else if (s.getValue().equals("Registering")) {
            return 3;
        } else if (s.getValue().equals("Completed")) {
            return 4;
        } else if s.getValue().equals("Aborted") {
            return 5;
        } else {
            return Integer.MAX_VALUE;
        }

    }

    public int compare(final State s1, final State s3)
    {
        return getRank(s1) - getRank(S2);
    }

}

Upvotes: 2

Naresh Joshi
Naresh Joshi

Reputation: 4537

You can create an enum like

public enum State {
    RUNNING, WAITING, REGISTERING, COMPLETED, ABORTED
}

By default, these states will get an ordinal integer which will be according to the order you write them in the enum. And then use this State as your state in your object and the create comparator

Comparator<MyClass> comparator = Comparator.comparing(MyClass::getState)
    .thenComparing(MyClass::getTimeStamp);

And then you can use the comparator to sort your collections

Upvotes: 0

Related Questions