1

So I'm trying to use the containsAll built in list method to compare two arrays

I used the contains method for single values and it works perfectly, however the contains all doesn't.

I'm making a card game so I'm checking whether a set of cards is also in another set of cards

so:

  if(this.hand.containsAll(hand.getCards())){

however this statement keeps returning false..

Here's the constructor

  private ArrayList<Card> hand;
     public Hand(ArrayList<Card> hand) {
            this();
            this.hand.addAll(hand);
        }

here's the get cards method

 public ArrayList<Card> getCards() {
        return this.hand;
    }

unsure as to why this code isn't returning true for containsAll but it's fine when done individually, is there some common concept that I haven't considered?

Any pointers would be a bonus

thank you

EDIT:

This returns true when used :

works

public boolean hasCard(Card card){
   if (this.hand.contains(card)){
       return true;
   }
}

doesn't

public boolean hasCards(Hand hand){
    if(this.hand.containsAll(hand.getCards()){
    return true
}
}

Main..

    Card one = new Card(Card.Rank.ACE, Card.Suit.CLUBS);
            Card two = new Card(Card.Rank.ACE, Card.Suit.DIAMONDS);
            Card three = new Card(Card.Rank.TWO, Card.Suit.SPADES);
            Card four = new Card(Card.Rank.SIX, Card.Suit.randSuit());
            Card five = new Card(Card.Rank.SEVEN, Card.Suit.randSuit());
            ArrayList<Card> cards = new ArrayList<>();
            cards.add(one);
            cards.add(two);
            cards.add(three);
            cards.add(four);
            cards.add(five);
            Hand h = new Hand(cards);


   Card ones = new Card(Card.Rank.ACE, Card.Suit.CLUBS);
        Card twos = new Card(Card.Rank.ACE, Card.Suit.DIAMONDS);
        Card threes = new Card(Card.Rank.TWO, Card.Suit.SPADES);
        ArrayList<Card> cards2 = new ArrayList<>();

// works
h.hasCard(five);

// doesn't
h.hasCards(h2);


        cards2.add(ones);
        cards2.add(twos);
        cards2.add(threes);
        Hand h2 = new Hand(cards2);
  • Is `this.hand` a `Hand` or `List` instance? – Tunaki Jan 16 '16 at 15:53
  • List instance @Tunaki –  Jan 16 '16 at 15:55
  • 2
    Did you implement the `equals` method in the `Card` class? – yole Jan 16 '16 at 15:57
  • No sir @yole, is that something I should avoid or do? –  Jan 16 '16 at 15:58
  • This is something you should read about, and then do. – yole Jan 16 '16 at 15:59
  • I'll have a look, thank you @yole –  Jan 16 '16 at 16:03
  • You said that `contains` works? Show that code. – Dima Jan 16 '16 at 16:07
  • sure one moment @Dima check edit –  Jan 16 '16 at 16:08
  • That's not "code", it's just a single statement. Show complete reproducible example that works with `contains` and does not with `containsAll`. Check out this link on how to ask good questions: http://stackoverflow.com/help/mcve – Dima Jan 16 '16 at 16:14
  • better? @DIma i've made another edit –  Jan 16 '16 at 16:20
  • Maybe because `card` is in `this.hand` but not all objects in `hand.getCards()` are in `this.hand` so you get false. Are you sure that all objects in `this.hand` List are exactly same as in `hand.getCards()` List? – Atri Jan 16 '16 at 16:26
  • thats not the problem because even if I just have the singular value for hand.getCards() for containsAll that I used previous for contains I still get false @Atri –  Jan 16 '16 at 16:28
  • Could you show the complete code for that? A minimal complete version which can be copy pasted and compiled without any change. – Atri Jan 16 '16 at 16:33
  • No, not "better": `if(this.hand.containsAll(hand.getCards())` does not make any sense, because `this.hand` and `hand` is the same thing, and you are treating it as a collection and as something that has `.getCards` at the same time – Dima Jan 16 '16 at 16:33
  • 1
    not the same thing, hence why I used this. @Dima, this. is referring the the object value and hand.getCards() is referring to the hand value passed in the argument.. thats just basic java –  Jan 16 '16 at 16:34
  • Share the complete code. – Abdul Razak Jan 16 '16 at 16:36
  • First of all, `h2` is defined below where you are using it. – Atri Jan 16 '16 at 16:42
  • @session_start there is no argument to that function, no local variable `hand`. Thus, `hand` and `this.hand` are the same thing in that scope. – Dima Jan 16 '16 at 16:46
  • You need to override the `equals()` method – Atri Jan 16 '16 at 16:47
  • I apologise @Dima, I corrected it –  Jan 16 '16 at 16:52
  • @session_start check my answer for "why". – Atri Jan 16 '16 at 17:03

2 Answers2

1

Try this h.hasCard(new Card(Card.Rank.ACE, Card.Suit.CLUBS)). It fill return false. But this h.hasCard(one) returns true.

To understand why, try this: one.equals(new Card(Card.Rank.ACE, Card.Suit.CLUBS). These are two instances of the same card, but java has no way of knowing about it. They are two different objects.

You added one to your h hand, so, when looking for that object, you find it. But searching for another object new Card(Card.Rank.ACE, Card.Suit.CLUBS) fails, because java does not know it represents the same card.

To fix this, you have to override the equals message on Card, and make it return true for objects that correspond to the same card.

Your containsAll call isn't working for the same reason: the hand contains all the cards, but they are represented by different objects. Implementing the equals method will fix that as well.

Dima
  • 39,570
  • 6
  • 44
  • 70
  • may I ask is my constructor public Hand(ArrayList hand) { this(); this.hand.addAll(hand); } a goodway to do it? –  Jan 16 '16 at 17:19
  • "A good way to do" ... _what_? Initialize the hand? It's ok ... I would declare the parameter as `List` or `Collection`, not `ArrayList`: the rule of thumb is to always use the most abstract interface level that fits your purpose. – Dima Jan 16 '16 at 17:29
  • so you'd have this.hand = new List<>(); –  Jan 16 '16 at 17:43
  • No, you can instantiate `List`, it's an interface. I am talking about the constructor parameter type, not the implementation. – Dima Jan 16 '16 at 17:46
1

You need to override the equals method.

When you do this:

Card five = new Card(Card.Rank.SEVEN, Card.Suit.randSuit());
h.hasCard(five);

You are essentially checking (five == five) which is true. This is because the default implementation of equals() method is (from the doc):

The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).

Now when you have h2 containing the following cards:

Card ones = new Card(Card.Rank.ACE, Card.Suit.CLUBS);
Card twos = new Card(Card.Rank.ACE, Card.Suit.DIAMONDS);
Card threes = new Card(Card.Rank.TWO, Card.Suit.SPADES);

and h the following cards:

    Card one = new Card(Card.Rank.ACE, Card.Suit.CLUBS);
    Card two = new Card(Card.Rank.ACE, Card.Suit.DIAMONDS);
    Card three = new Card(Card.Rank.TWO, Card.Suit.SPADES);
    Card four = new Card(Card.Rank.SIX, Card.Suit.randSuit());
    Card five = new Card(Card.Rank.SEVEN, Card.Suit.randSuit());

And then you do:

h.hasCards(h2);

Then you are essentially checking if ones, twos and threes are present in h. Which is false, because for instance ones is NOT == any object in h.

You can check this for yourself by printing the value of (ones == one) which will be false.

Solution:

If you override the equals() method in your Class Card something like:

@Override
public boolean equals(Object o) {

    // Check if o == itself  
    if (o == this) {
        return true;
    }

    // Check to see if o is instance of Card or not
    if (!(o instanceof Card)) {
        return false;
    }

    // typecast o to Card to compare 
    Card c = (Card) o;

    // check equality (assuming Rank and Suit to be int, else you need to change equality condition here)
    return this.Rank == c.Rank
            && this.Suit == c.Suit;
}
Atri
  • 5,511
  • 5
  • 30
  • 40
  • Would the fact that I'm using enums be a problem? Also Complex isn't showing for me @Atri –  Jan 16 '16 at 17:10
  • @session_start sorry my bad, I was using my template of equals. – Atri Jan 16 '16 at 17:39
  • @session_start For comparing enums check this : http://stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals – Atri Jan 16 '16 at 17:50
  • what is the point of the Card c= (Card) o when you're not using c? @Atri –  Jan 16 '16 at 20:10