Java 에서 리스트에 중복 요소가 있는지 확인하는 방법

JavaBeginner
지금 연습하기

소개

이 랩에서는 Java List에 중복된 요소가 있는지 효율적으로 확인하는 방법을 배우게 됩니다. HashSet 데이터 구조를 사용하여 일반적이고 효과적인 기술을 탐구할 것입니다.

먼저, HashSet의 고유 요소 속성을 활용하여 리스트를 반복하고 요소를 세트에 추가하여 중복을 감지하는 메서드를 구현합니다. 요소가 이미 세트에 존재하면 중복이 발견된 것입니다. 그 다음, 원래 리스트의 크기와 리스트의 요소로 채워진 HashSet의 크기를 비교하는 대체 접근 방식을 배우게 됩니다. 마지막으로, 견고성을 보장하기 위해 null 및 빈 리스트를 포함한 다양한 시나리오로 구현을 테스트합니다.

HashSet 을 사용하여 중복 감지

이 단계에서는 Java 에서 HashSet을 사용하여 컬렉션 내에서 중복 요소를 효율적으로 감지하는 방법을 살펴봅니다. HashSet은 Java Collections Framework 의 일부이며 고유한 요소를 저장하는 데 특히 유용합니다.

먼저, ~/project 디렉토리에 DuplicateDetector.java라는 새 Java 파일을 생성해 보겠습니다. 웹 IDE 의 왼쪽 File Explorer 를 사용하여 이 작업을 수행할 수 있습니다. ~/project 영역을 마우스 오른쪽 버튼으로 클릭하고 "New File"을 선택한 다음 DuplicateDetector.java를 입력합니다.

이제 Code Editor 에서 DuplicateDetector.java 파일을 열고 다음 코드를 추가합니다.

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class DuplicateDetector {

    public static boolean containsDuplicates(List<String> list) {
        // Create a HashSet to store unique elements
        Set<String> uniqueElements = new HashSet<>();

        // Iterate through the list
        for (String element : list) {
            // If the element is already in the HashSet, it's a duplicate
            if (uniqueElements.contains(element)) {
                return true; // Found a duplicate
            }
            // Otherwise, add the element to the HashSet
            uniqueElements.add(element);
        }

        // If the loop finishes without finding duplicates, return false
        return false;
    }

    public static void main(String[] args) {
        // Example usage
        List<String> myListWithDuplicates = new ArrayList<>();
        myListWithDuplicates.add("apple");
        myListWithDuplicates.add("banana");
        myListWithDuplicates.add("apple"); // Duplicate
        myListWithDuplicates.add("orange");

        List<String> myListWithoutDuplicates = new ArrayList<>();
        myListWithoutDuplicates.add("grape");
        myListWithoutDuplicates.add("mango");
        myListWithoutDuplicates.add("kiwi");

        System.out.println("List with duplicates: " + myListWithDuplicates);
        System.out.println("Contains duplicates? " + containsDuplicates(myListWithDuplicates)); // Expected: true

        System.out.println("\nList without duplicates: " + myListWithoutDuplicates);
        System.out.println("Contains duplicates? " + containsDuplicates(myListWithoutDuplicates)); // Expected: false
    }
}

이 코드의 주요 부분을 이해해 보겠습니다.

  • import java.util.ArrayList;, import java.util.HashSet;, import java.util.List;, import java.util.Set;: 이 줄은 Java Collections Framework 에서 필요한 클래스를 가져옵니다.
  • public static boolean containsDuplicates(List<String> list): 이것은 String 객체의 List를 입력으로 받아 중복이 있으면 true를 반환하고 그렇지 않으면 false를 반환하는 메서드입니다.
  • Set<String> uniqueElements = new HashSet<>();: 이것은 uniqueElements라는 빈 HashSet을 생성합니다. HashSet은 고유한 요소만 저장하도록 설계되었습니다.
  • for (String element : list): 이 루프는 입력 list의 각 element를 반복합니다.
  • if (uniqueElements.contains(element)): 이 코드는 현재 element가 이미 uniqueElements HashSet에 있는지 확인합니다. 그렇다면 중복을 찾은 것이므로 메서드는 true를 반환합니다.
  • uniqueElements.add(element);: 요소가 HashSet에 아직 없으면 추가됩니다. HashSet은 고유한 요소만 저장하므로 이미 있는 요소를 추가해도 아무런 효과가 없습니다.
  • return false;: 루프가 중복을 찾지 않고 완료되면 메서드는 false를 반환합니다.
  • main 메서드는 예제 목록과 함께 containsDuplicates 메서드를 사용하는 방법을 보여줍니다.

DuplicateDetector.java 파일을 저장합니다 (Ctrl+S 또는 Cmd+S).

이제 Terminal 에서 이 프로그램을 컴파일하고 실행해 보겠습니다. ~/project 디렉토리에 있는지 확인하십시오.

코드를 컴파일합니다.

javac DuplicateDetector.java

컴파일 오류가 없으면 출력이 표시되지 않습니다.

이제 컴파일된 코드를 실행합니다.

java DuplicateDetector

다음과 유사한 출력이 표시됩니다.

List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true

List without duplicates: [grape, mango, kiwi]
Contains duplicates? false

이 출력은 containsDuplicates 메서드가 중복이 있는 목록을 올바르게 식별했음을 확인합니다. HashSet을 사용하는 것은 HashSet에서 요소의 존재 여부를 확인하는 것 (contains()) 이 평균적으로 매우 빠르기 때문에 중복을 확인하는 효율적인 방법입니다.

리스트 크기와 세트 크기 비교

이전 단계에서는 HashSet을 사용하여 리스트를 반복하고 요소를 세트에 추가하여 중복을 확인했습니다. 중복을 감지하는 더 간단하고 종종 더 효율적인 방법은 원래 리스트의 크기와 해당 리스트에서 생성된 HashSet의 크기를 비교하는 것입니다.

HashSet은 고유한 요소만 저장한다는 것을 기억하십시오. 리스트에 중복이 포함된 경우 해당 리스트에서 생성된 HashSet의 크기는 원래 리스트의 크기보다 작습니다. 중복이 없으면 크기가 같습니다.

이 접근 방식을 구현하기 위해 DuplicateDetector.java 파일을 수정해 보겠습니다. Code Editor 에서 ~/project/DuplicateDetector.java를 엽니다.

containsDuplicates 메서드를 다음 코드로 바꿉니다.

    public static boolean containsDuplicates(List<String> list) {
        // Create a HashSet from the list
        Set<String> uniqueElements = new HashSet<>(list);

        // Compare the size of the list with the size of the HashSet
        return list.size() != uniqueElements.size();
    }

새 코드에서 무슨 일이 일어나고 있는지 살펴보겠습니다.

  • Set<String> uniqueElements = new HashSet<>(list);: 이 줄은 HashSet을 직접 생성하고 입력 list의 모든 요소로 초기화합니다. HashSet은 자동으로 고유성을 처리하므로 리스트의 중복 요소는 세트에 추가되지 않습니다.
  • return list.size() != uniqueElements.size();: 이 줄은 원래 list의 요소 수 (list.size()) 를 HashSet의 고유 요소 수 (uniqueElements.size()) 와 비교합니다. 크기가 다르면 (!=) 리스트에 중복이 있었음을 의미하며 메서드는 true를 반환합니다. 크기가 같으면 중복이 없었으므로 메서드는 false를 반환합니다.

main 메서드는 이미 containsDuplicates 메서드를 호출하므로 동일하게 유지될 수 있습니다.

DuplicateDetector.java 파일을 저장합니다 (Ctrl+S 또는 Cmd+S).

이제 수정된 프로그램을 컴파일하고 실행해 보겠습니다. Terminal 에서 ~/project 디렉토리에 있는지 확인하십시오.

코드를 컴파일합니다.

javac DuplicateDetector.java

컴파일된 코드를 실행합니다.

java DuplicateDetector

이전과 동일한 출력이 표시됩니다.

List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true

List without duplicates: [grape, mango, kiwi]
Contains duplicates? false

이것은 크기 비교를 사용하여 중복을 감지하는 새롭고 더 간단한 메서드가 올바르게 작동함을 확인합니다. 이 접근 방식은 일반적으로 특히 더 큰 리스트의 경우 하나씩 반복하고 포함 여부를 확인하는 것보다 더 간결하고 종종 더 효율적입니다.

Null 및 빈 리스트로 테스트

실제 프로그래밍에서는 리스트가 비어 있거나 심지어 null인 경우와 같은 엣지 케이스 (edge case) 를 고려하는 것이 중요합니다. 현재 containsDuplicates 메서드는 요소가 있는 리스트에 대해 잘 작동하지만, 빈 리스트 또는 null 리스트를 전달하면 어떻게 될까요?

~/project/DuplicateDetector.javamain 메서드에 더 많은 예제를 추가하여 이를 테스트해 보겠습니다. Code Editor 에서 파일을 열고 기존 코드 뒤에 다음 줄을 main 메서드에 추가합니다.

        System.out.println("\nEmpty list: " + new ArrayList<>());
        System.out.println("Contains duplicates? " + containsDuplicates(new ArrayList<>())); // Expected: false

        List<String> nullList = null;
        System.out.println("\nNull list: " + nullList);
        // The following line will cause a NullPointerException if not handled
        // System.out.println("Contains duplicates? " + containsDuplicates(nullList));

파일을 저장합니다 (Ctrl+S 또는 Cmd+S).

이제 프로그램을 다시 컴파일하고 실행합니다.

컴파일:

javac DuplicateDetector.java

실행:

java DuplicateDetector

빈 리스트에 대한 출력을 볼 수 있습니다.

List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true

List without duplicates: [grape, mango, kiwi]
Contains duplicates? false

Empty list: []
Contains duplicates? false

빈 리스트에 대한 출력은 올바릅니다. 빈 리스트에는 중복이 포함되어 있지 않습니다.

그러나 System.out.println("Contains duplicates? " + containsDuplicates(nullList)); 줄의 주석 처리를 해제하고 컴파일 및 실행을 시도하면 NullPointerException이 발생합니다. 이는 null 리스트에서 HashSet을 생성하려고 시도하기 때문이며, 이는 허용되지 않습니다.

containsDuplicates 메서드를 더 강력하게 만들려면 입력 리스트가 null인 경우를 처리해야 합니다. 메서드 시작 부분에 검사를 추가할 수 있습니다.

~/project/DuplicateDetector.javacontainsDuplicates 메서드를 수정하여 null 검사를 포함합니다.

    public static boolean containsDuplicates(List<String> list) {
        // Handle null input
        if (list == null) {
            return false; // A null list does not contain duplicates
        }

        // Create a HashSet from the list
        Set<String> uniqueElements = new HashSet<>(list);

        // Compare the size of the list with the size of the HashSet
        return list.size() != uniqueElements.size();
    }

이제 main 메서드에서 null 리스트를 테스트하는 줄의 주석 처리를 해제합니다.

        List<String> nullList = null;
        System.out.println("\nNull list: " + nullList);
        System.out.println("Contains duplicates? " + containsDuplicates(nullList)); // Expected: false

파일을 저장합니다 (Ctrl+S 또는 Cmd+S).

프로그램을 마지막으로 컴파일하고 실행합니다.

컴파일:

javac DuplicateDetector.java

실행:

java DuplicateDetector

이제 출력에는 충돌 없이 null 리스트에 대한 결과가 포함되어야 합니다.

List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true

List without duplicates: [grape, mango, kiwi]
Contains duplicates? false

Empty list: []
Contains duplicates? false

Null list: null
Contains duplicates? false

null 검사를 추가함으로써 containsDuplicates 메서드는 이제 더 강력해졌으며 null 입력을 정상적으로 처리할 수 있습니다. 이는 예기치 않은 오류를 방지하기 위한 프로그래밍의 중요한 관행입니다.

요약

이 랩에서는 Java List에 중복 요소가 포함되어 있는지 확인하는 방법을 배웠습니다. 효율적인 중복 감지를 위해 HashSet을 사용하는 방법을 살펴보았습니다. 리스트를 반복하고 각 요소를 HashSet에 추가하려고 시도함으로써 요소가 이미 있는지 빠르게 확인할 수 있으며, 이는 중복을 나타냅니다.

또한 원래 리스트의 크기와 리스트에서 생성된 HashSet의 크기를 비교하는 대체 방법을 배웠습니다. 크기가 다르면 중복이 있음을 나타냅니다. 마지막으로, 견고성을 보장하기 위해 null 및 빈 리스트로 메서드를 테스트하여 엣지 케이스 (edge case) 를 고려했습니다.