Reputation: 832
I have a class, Card
:
public class Card implements Comparable<Card> {
public enum rank {TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE};
private rank Rank;
public enum suit {CLUBS, DIAMONDS, HEARTS, SPADES};
private suit Suit;
}
Which I need to perform two tasks on. First - Make the Card class Comparable, so that compareTo can be used to sort the cards into ascending order. I've done this here:
@Override
public int compareTo(Card other) {
if(this.Rank != other.Rank) {
if(this.Rank.ordinal() > other.Rank.ordinal()) {
return 1;
}
else if(this.Rank.ordinal() < other.Rank.ordinal()) {
return -1;
}
else {
return 0;
}
}
else {
if(this.Suit.ordinal() > other.Suit.ordinal()) {
return 1;
}
else if(this.Suit.ordinal() < other.Suit.ordinal()) {
return -1;
}
else {
return 0;
}
}
}
and secondly - Add a Comparator class as a nested classes of the Card class called CompareDescending. This should be used to sort the cards into descending order. I've done this here, and it works well:
public static class CompareDescending implements Comparator<Card> {
@Override
public int compare(Card card, Card other) {
if(card.Rank != other.Rank) {
if(card.Rank.ordinal() < other.Rank.ordinal()) {
return 1;
}
else if(card.Rank.ordinal() > other.Rank.ordinal()) {
return -1;
}
else {
return 0;
}
}
else {
if(card.Suit.ordinal() < other.Suit.ordinal()) {
return 1;
}
else if(card.Suit.ordinal() > other.Suit.ordinal()) {
return -1;
}
else {
return 0;
}
}
}
}
However, I wondered if I've gone about this the wrong way. Should my nested Comparator class use the compareTo() function inside it? Is this better practice?
Upvotes: 1
Views: 777
Reputation: 18245
You custom comparator is very complex. Comparator
class provides suitable method to make custom comparator easier. Additionally, enum
implements natural order comparator.
To create descending order comparator you do not have to rewrite existed asceding order comparator. Just call Comparator.reverseOrder()
before.
class Card implements Comparable<Card> {
public static final Comparator<Card> SORT_ASC = Comparator.<Card, Rank>comparing(card -> card.rank).thenComparing(card -> card.suit);
public static final Comparator<Card> SORT_DESC = SORT_ASC.reversed();
private Rank rank;
private Suit suit;
@Override
public int compareTo(Card card) {
return SORT_ASC.compare(this, card);
}
public enum Rank {}
public enum Suit {}
}
Demo
List<Card> cards = Collections.emptyList();
List<Card> asc = cards.stream().sorted(Card.SORT_ASC).collect(Collectors.toList());
List<Card> desc = cards.stream().sorted(Card.SORT_DESC).collect(Collectors.toList());
Upvotes: 0
Reputation: 159086
Your compareTo
is overly complex.
enum
implements a compareTo
for you, for ordering enum values in the declared order, i.e. by ordinal.
That means your code can simply be:
@Override
public int compareTo(Card other) {
int cmp = this.Rank.compareTo(other.Rank);
if (cmp == 0)
cmp = this.Suit.compareTo(other.Suit);
return cmp;
}
To compare in reverse order, you simply flip the objects being compared, i.e. instead of a.compareTo(b)
you write b.compareTo(a)
, so a descending Comparator
implementation would be:
public static class CompareDescending implements Comparator<Card> {
@Override
public int compare(Card card, Card other) {
return other.compareTo(card); // descending
}
}
It is a good idea to document (comment) that the comparison is reversed, because casual review of the code might very easily miss that. Here, I have documented it by simply commenting that the compare is "descending".
Upvotes: 5