Trompetas Rouketas
Trompetas Rouketas

Reputation: 96

How to use the Comparator interface in Java?

I can't figure out how to properly use the Comparator interface.

NOTE: I don't want to use the "one line" comparator implementation I see on most code, meaning :

Collections.sort(deck, new Comparator<Card>() {
  @Override
  public int compare(Card o1, Card o2) {
   return WHATEVER;
  });

Again, I don't want to use this, because I'm going to be sorting many different ArrayLists and it seems like a waste of space to do that every time. I want to somehow make it work, having my compareTo method written once in one place.

I tried many different things, but I'm new to implementing interfaces, so I'm probably missing something.

This is my Card class with it's compare method. (NOTE: Let me save you some time and say that I'm not interested in using Enumerations to simplify the code and the comparison, I just want to learn how to use Comparator properly. I know it looks bad but I have to use some already written code. )

import java.util.*;
public class Card implements Comparator<Card>
{
    private String number;
    private int value;
    private int finalValue;
    private String suit;
    private Player owner;

    public Card(String number, String suit)
    {
        this.number=number;
        switch (number){
            case "2": this.value = 2;
                break;
            case "3": this.value = 3;
                break;
            case "4": this.value = 4;
                break;
            case "5": this.value = 5;
                break;    
            case "6": this.value = 6;
                break;
            case "7": this.value = 7;
                break;
            case "8": this.value = 8;
                break;    
            case "9": this.value = 9;
                break;
            case "10": this.value = 10;
                break;
            case "J": this.value = 11;
                break;
            case "Q": this.value = 12;
                break;
            case "K": this.value = 13;
                break;
            case "A": this.value = 14;
                break;
            }

        this.suit=suit;
        switch (suit){
            case "Spades": this.finalValue = this.value*4;
                break;
            case "Hearts": this.finalValue = this.value*5;
                break;
            case "Clubs": this.finalValue = this.value*2;
                break;
            case "Diamonds": this.finalValue = this.value*3;
                break;
            }
    }

    public int compare(Card card1, Card card2)
    {
        Integer suitValue1;
        if (card1.getSuit() == "Hearts")
        suitValue1=5;
        else if (card1.getSuit() == "Spades")
        suitValue1=4;
        else if (card1.getSuit() == "Diamonds")
        suitValue1=3;
        else
        suitValue1=2;

        Integer suitValue2;
        if (card2.getSuit() == "Hearts")
        suitValue2=5;
        else if (card2.getSuit() == "Spades")
        suitValue2=4;
        else if (card2.getSuit() == "Diamonds")
        suitValue2=3;
        else
        suitValue2=2;

        Integer value1, value2;
        value1 = card1.getValue();
        value2 = card2.getValue();

        if (suitValue1 != suitValue2)
        return suitValue1.compareTo(suitValue2);
        else
        return value1.compareTo(value2);

    }

    //get methods
    public int getValue()
    {return this.value;}

    public int getFinalValue()
    {return this.finalValue;}

    public String getNumber()
    {return this.number;}

    public String getSuit()
    {return this.suit;}

    public Player getOwner()
    {return this.owner;}

    //set methods
    public void setValue(int value)
    {this.value = value;}

    public void setFinalValue(int finalValue)
    {this.finalValue = finalValue;}

    public void setNumber(String number)
    {this.number = number;}

    public void setSuit(String suit)
    {this.suit = suit;}

    public void setOwner(Player player)
    {this.owner = player;}

}

So that's my compare method. Should I put it in another class or something? I try to call it using this:

Collections.sort(deck, new Comparator<Card>());

but that is obviously wrong.

deck is an ArrayList : private ArrayList<Card> deck = new ArrayList<Card>(); filled with various Card objects.

Upvotes: 1

Views: 1178

Answers (6)

Greg
Greg

Reputation: 617

i think this is what you intended. I don't believe you can use a switch statement on Strings unless you are 1.7+

public class Card implements Comparable<Card>
{
    private String number;
    private int value;
    private int finalValue;
    private String suit;
    private Player owner;

    public Card(String number, String suit)
    {
        this.number = number;
        this.value = 0;
        this.finalValue = 0;


        //card value
        if ("2".equalsIgnoreCase(number))
        {
            this.value = 2;
        }
        else if ("3".equalsIgnoreCase(number))
        {
            this.value = 3;

        }
        else if ("4".equalsIgnoreCase(number))
        {
            this.value = 4;

        }
        else if ("5".equalsIgnoreCase(number))
        {
            this.value = 5;

        }
        else if ("6".equalsIgnoreCase(number))
        {
            this.value = 6;

        }
        else if ("7".equalsIgnoreCase(number))
        {
            this.value = 7;

        }
        else if ("8".equalsIgnoreCase(number))
        {
            this.value = 8;

        }
        else if ("9".equalsIgnoreCase(number))
        {
            this.value = 9;
        }
        else if ("10".equalsIgnoreCase(number))
        {
            this.value = 10;
        }
        else if ("J".equalsIgnoreCase(number))
        {
            this.value = 11;

        }
        else if ("Q".equalsIgnoreCase(number))
        {
            this.value = 12;
        }
        else if ("K".equalsIgnoreCase(number))
        {
            this.value = 13;

        }
        else if ("A".equalsIgnoreCase(number))
        {
            this.value = 14;
        }


        //suits
        if ("Spades".equalsIgnoreCase(number))
        {
            this.finalValue = this.value * 4;
        }
        else if ("Hearts".equalsIgnoreCase(number))
        {
            this.finalValue = this.value * 5;

        }
        else if ("Clubs".equalsIgnoreCase(number))
        {
            this.finalValue = this.value * 2;

        }
        else if ("Diamonds".equalsIgnoreCase(number))
        {
            this.finalValue = this.value * 3;

        }

    }


    @Override
    public int compareTo(Card o)
    {
        final int EQUAL = 0;
        final int LESS_THAN = -1;
        final int GREATER_THAN = 1;

        if (this == o || this.getFinalValue() == o.getFinalValue())
        {
            return EQUAL;
        }
        else if (this.getFinalValue() < o.getFinalValue())
        {
            return LESS_THAN;
        }
        else
        {
            return GREATER_THAN;
        }
    }

    // get methods
    public int getValue()
    {
        return this.value;
    }

    public int getFinalValue()
    {
        return this.finalValue;
    }

    public String getNumber()
    {
        return this.number;
    }

    public String getSuit()
    {
        return this.suit;
    }

    public Player getOwner()
    {
        return this.owner;
    }

    // set methods
    public void setValue(int value)
    {
        this.value = value;
    }

    public void setFinalValue(int finalValue)
    {
        this.finalValue = finalValue;
    }

    public void setNumber(String number)
    {
        this.number = number;
    }

    public void setSuit(String suit)
    {
        this.suit = suit;
    }

    public void setOwner(Player player)
    {
        this.owner = player;
    }
}

Upvotes: -1

Vidya
Vidya

Reputation: 30310

You are confusing Comparable with Comparator. They are similar of course but really fundamentally different.

Comparable defines the natural ordering of a class--how instances of your class should sort themselves by default. That's actually what you want here.

Comparator helps you to sort the instances of your class when you want to use a different sort order than the natural order. That doesn't seem to be your aim here.

So what you actually want is this:

public class Card implements Comparable<Card> {
  public int compareTo(Card otherCard) {
    //return 1 when this instance is greater than the parameter, -1 if less; 0 if equal
  } 

  //Other stuff
  //And make sure compareTo is consistent with equals
}

Note that the method you have to implement is compareTo, which is different from what you implement with Comparator.

Then you simply sort this way:

Collections.sort(deck)

And the cards will know how to sort themselves.

If you need more guidance, we actually did a tutorial on Comparable and Comparator with the files available on Github. Check it out if you like.

Upvotes: 4

JEuvin
JEuvin

Reputation: 1039

I agree with Juned, use value1.equals(value2) this returns a boolean. From the looks of things you only doing string comparison which is fairly stright forward.

Good luck.

Upvotes: 0

jfisher
jfisher

Reputation: 11

To summarize:

  • To sort the array use Collections.sort(deck);
  • Your Card class needs to implement Comparable
  • When comparing Strings its best to use equals
  • It is better to use the constant String first ie "Hearts".equals(this.getSuit()), this will guard against Null pointers

Upvotes: 1

Jon Kiparsky
Jon Kiparsky

Reputation: 7743

You want to implement Comparable, and then you can just sort the array.

Upvotes: 0

Lake
Lake

Reputation: 4092

Since you seem to have one only way to compare Card objects, you don't really have to use a Comparator. Let Card implement Comparable, instead, and then sort by the 1-parameter method:

Collections.sort(deck);

Upvotes: 1

Related Questions