List 에 중복 객체를 가지고 있는데 순서를 고려하지 않고 equals 검사를 하고 싶어요

Lily·2024년 3월 24일
5
post-thumbnail

🃏 List 가 담고있는 객체의 구성과 개수가 같으면 같다고 반환하기

일단 내가 하고싶었던 것은 List<Card> 끼리의 equals 비교이다
그럼 그냥 하면 되지 왜 그러냐 하면 ..
카드덱을 여러개 쓰기 때문에 같은 Card 가 들어갈 수 있고, 순서와 상관없이 가지고 있는 Card가 모두 같으면 같다고 반환했으면 했다!

MISSION : List<5클로버, 2하트, 2하트> 와 List<2하트, 5클로버, 2하트> 를 같은 객체로 취급하기

여기서 핵심은 중복 객체를 허용하면서 순서는 고려하지 않는것 이다

이로 인해 겪었던 문제는

  • List 는 중복을 허용하고 순서를 고려한다
    -> 다시 말해서, 순서가 다르면 다른 객체라고 판단한다

♣️♥️ 해결 흐름을 따라가보자

⬇️ 우선 List<Card> 를 가지고 있는 Cards 에서 equals 와 hashCode 구현을 해주었다

@Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Cards cards1 = (Cards) o;
        return Objects.equals(cards, cards1.cards);
    }

@Override
    public int hashCode() {
        return Objects.hash(cards);
    }

이렇게만 해주면 equals 비교가 제대로 될 것인지 고민을 해봐야 한다 🤔

우선 List 의 equals() 메서드는 다음과 같은 방식으로 동작한다

  1. 비교하는 두 리스트의 크기가 같은지 확인하고 -> 만약 크기가 다르면 false 를 반환한다
  2. 두 리스트의 각 요소를 순서대로 비교한다. 이 때 equals() 메서드를 사용하여 요소를 비교한다.
  3. 모든 요소가 서로 동일한지 확인한 후에 두 리스트가 동일한지 여부를 결정한다

여기서 주의해야할 점은,
리스트 요소의 equals() 메서드는 해당 요소들의 타입에 따라 다르게 작동할 수 있다

  • 만약 요소가 사용자 정의 클래스 객체라면 해당 클래스에서 equals() 메서드를 오버라이드하여 적절한 동등성 검사를 구현해야한다.
    만약 기본 자료형이라면 값이 같은지를 비교한다.

⬇️ 따라서 내가 비교하려는 List 의 요소는 Card, 즉 사용자 정의 클래스 객체이기 때문에 Card 클래스에 equals 와 hashCode 를 추가로 구현해주었다

 @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Card card = (Card) o;
        return number == card.number && shape == card.shape;
    }

    @Override
    public int hashCode() {
        return Objects.hash(number, shape);
    }```

이제 List<Card> 의 equals 비교는 제대로 작동한다 !

여기까지 하면 Card 의 구성과 순서가 같으면 같은 List 라고 반환한다

🤭 이제 Card 순서와 상관없이 구성과 개수가 같으면 같다고 반환해보자

List<Card> 의 equals 구현을 수정해줘야 하는데, Set 을 이용하기엔 중복을 허용하지 않아서 카드 구성만 같으면 각 카드의 개수가 달라도 true 를 반환할 것 같고 해서 찾은 방법은 ..
HashMap 너 나와 !

  Map<Card, Integer> cardCount = new HashMap<>();

List<Card> 에서 Card 와 그 Card 의 개수 를 담는 HashMap 을 이용할 것이다

Cards 객체에 toHashMap 메서드를 추가로 구현해주었다

private Map<Card, Integer> toHashMap() {
      Map<Card, Integer> cardCount = new HashMap<>();
      for (Card card : cards) {
          cardCount.putIfAbsent(card, 1);
          cardCount.computeIfPresent(card, (k, v) -> v + 1);
      }
      return cardCount;
  }

짠 - 이제 다 왔다 !
이걸 이용해서 equals 검사를 수정해주면 된다

@Override
  public boolean equals(Object o) {
      if (this == o) {
          return true;
      }
      if (o == null || getClass() != o.getClass()) {
          return false;
      }
      Cards cardsForCompare = (Cards) o;
      Map<Card, Integer> cardsCount = cardsForCompare.toHashMap();
      return cardsCount.equals(this.toHashMap());
  }

@Override
  public int hashCode() {
      return Objects.hash(cards);
  }

😮🥹 완성되었다

equals 와 hashCode 는 인텔리제이에서 편리하게 사용할 수 있게 클래스에서 cmd + n 누르고 Generate 하기만 하면 자동으로 작성을 해주기에 직접 작성할 일도, 커스터마이징 할 일도 없었는데 이번 기회로 (아주)조금 더 java 와 친해진 계기가 된 것 같다

끄읏

profile
내가 하고 싶은 거

0개의 댓글

관련 채용 정보