Java 컬렉션에서 중복 요소 확인하는 방법

JavaBeginner
지금 연습하기

소개

이 랩에서는 Java 컬렉션 내에서 중복 요소를 효율적으로 확인하는 방법을 배우게 됩니다. 중복을 식별하기 위해 Java Collections Framework 의 강력한 도구인 HashSet의 사용법을 살펴봅니다.

실습 단계를 통해 먼저 HashSet의 고유 요소 속성을 활용하여 중복을 감지하는 방법을 배우게 됩니다. 그런 다음, 원래 컬렉션과 이로부터 생성된 HashSet의 크기를 비교하는 대체 방법을 발견하게 됩니다. 마지막으로, 중복을 확인할 때 null 요소를 처리하는 방법을 살펴보겠습니다.

HashSet 을 사용하여 중복 확인

이 단계에서는 Java 에서 HashSet을 사용하여 컬렉션 내의 중복 요소를 효율적으로 확인하는 방법을 살펴보겠습니다. HashSet은 Java Collections Framework 의 일부이며, 고유한 요소를 저장하고 매우 빠른 조회를 제공하기 때문에 특히 유용합니다.

먼저, ~/project 디렉토리에 DuplicateCheck.java라는 새 Java 파일을 생성해 보겠습니다. WebIDE 파일 목록 영역에서 마우스 오른쪽 버튼을 클릭하고 "New File"을 선택한 다음 DuplicateCheck.java를 입력하여 직접 수행할 수 있습니다.

이제 코드 편집기에서 DuplicateCheck.java 파일을 열고 다음 코드를 추가합니다.

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

public class DuplicateCheck {

    public static void main(String[] args) {
        // Create a list with some duplicate elements
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Alice"); // Duplicate
        names.add("Charlie");
        names.add("Bob"); // Duplicate

        System.out.println("Original List: " + names);

        // Use a HashSet to find duplicates
        Set<String> uniqueNames = new HashSet<>();
        Set<String> duplicates = new HashSet<>();

        for (String name : names) {
            if (!uniqueNames.add(name)) {
                // If add returns false, the element is already in the set
                duplicates.add(name);
            }
        }

        System.out.println("Duplicates found: " + duplicates);
    }
}

이 코드의 새로운 부분을 자세히 살펴보겠습니다.

  • import java.util.ArrayList;, import java.util.HashSet;, import java.util.List;, import java.util.Set;: 이 줄은 목록 및 집합으로 작업하기 위해 Java 유틸리티 라이브러리에서 필요한 클래스를 가져옵니다.
  • List<String> names = new ArrayList<>();: String 객체를 담을 수 있는 names라는 List를 생성합니다. List 인터페이스의 특정 구현으로 ArrayList를 사용합니다.
  • names.add(...): names 목록에 요소를 추가합니다. "Alice"와 "Bob"이 두 번 추가된 것을 확인하세요.
  • Set<String> uniqueNames = new HashSet<>();: HashSet 구현을 사용하여 uniqueNames라는 Set을 생성합니다. Set은 고유한 요소만 포함하도록 보장합니다.
  • Set<String> duplicates = new HashSet<>();: 찾은 중복 요소를 저장하기 위해 다른 Set을 생성합니다.
  • for (String name : names): names 목록의 각 name을 반복하는 for-each 루프입니다.
  • if (!uniqueNames.add(name)): HashSetadd() 메서드는 요소가 성공적으로 추가된 경우 (Set에 이미 없는 경우) true를 반환하고, 요소가 이미 있는 경우 false를 반환합니다. !는 결과를 부정하므로, add()false를 반환하는 경우에만 if 블록 내부의 코드가 실행되어 중복을 나타냅니다.
  • duplicates.add(name);: 중복이 발견되면 duplicates 집합에 추가합니다.

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

이제 WebIDE 하단의 터미널을 엽니다. ~/project 디렉토리에 있는지 확인합니다. pwd를 입력하고 Enter 키를 눌러 확인할 수 있습니다. 출력은 /home/labex/project여야 합니다.

javac 명령을 사용하여 Java 프로그램을 컴파일합니다.

javac DuplicateCheck.java

오류가 없으면 출력이 표시되지 않습니다. 이는 컴파일이 성공적으로 완료되었고 DuplicateCheck.class 파일이 ~/project 디렉토리에 생성되었음을 의미합니다. ls 명령을 실행하여 확인할 수 있습니다.

마지막으로, java 명령을 사용하여 컴파일된 Java 프로그램을 실행합니다.

java DuplicateCheck

다음과 유사한 출력이 표시되어야 합니다.

Original List: [Alice, Bob, Alice, Charlie, Bob]
Duplicates found: [Alice, Bob]

Duplicates found 출력의 요소 순서는 HashSet이 삽입 순서를 유지하지 않기 때문에 다를 수 있습니다.

HashSet을 사용하여 목록에서 중복 요소를 성공적으로 식별했습니다!

컬렉션과 Set 크기 비교

이전 단계에서는 HashSet을 사용하여 중복 요소를 찾았습니다. Set의 주요 특징은 고유한 요소만 저장한다는 것입니다. 즉, 중복 요소를 Set에 추가하면 각 요소의 인스턴스 하나만 유지됩니다. 이 속성은 목록에서 중복을 제거하는 것과 같은 작업에 매우 유용합니다.

이 단계에서는 DuplicateCheck.java 프로그램을 수정하여 원래 목록 (중복을 포함할 수 있음) 의 크기를 해당 목록에서 생성된 HashSet(고유한 요소만 포함) 의 크기와 비교하여 이 속성을 시연합니다.

WebIDE 코드 편집기에서 DuplicateCheck.java 파일을 엽니다.

main 메서드를 다음과 같이 수정합니다.

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

public class DuplicateCheck {

    public static void main(String[] args) {
        // Create a list with some duplicate elements
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Alice"); // Duplicate
        names.add("Charlie");
        names.add("Bob"); // Duplicate
        names.add("David");

        System.out.println("Original List: " + names);
        System.out.println("Size of Original List: " + names.size());

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

        System.out.println("Set created from List: " + uniqueNamesSet);
        System.out.println("Size of Set: " + uniqueNamesSet.size());

        // The difference in size tells us how many duplicates were removed
        int duplicatesCount = names.size() - uniqueNamesSet.size();
        System.out.println("Number of duplicates (excluding first occurrence): " + duplicatesCount);
    }
}

다음은 추가하거나 변경한 내용입니다.

  • names 목록에 "David"라는 다른 이름을 추가하여 목록을 약간 더 크게 만들었습니다.
  • System.out.println("Size of Original List: " + names.size());: size() 메서드를 사용하여 원래 목록의 크기를 출력합니다.
  • Set<String> uniqueNamesSet = new HashSet<>(names);: 다른 Collection(예: ArrayList) 에서 직접 HashSet을 생성하는 편리한 방법입니다. 이렇게 하면 HashSet이 목록의 모든 요소를 자동으로 추가하고, Set이므로 중복을 모두 삭제합니다.
  • System.out.println("Size of Set: " + uniqueNamesSet.size());: HashSet의 크기를 출력합니다. 이 크기는 고유한 요소의 수를 나타냅니다.
  • int duplicatesCount = names.size() - uniqueNamesSet.size();: 목록 크기와 집합 크기의 차이를 계산합니다. 이 차이는 중복된 요소의 수 (첫 번째 발생 이후) 를 알려줍니다.

수정된 DuplicateCheck.java 파일을 저장합니다.

이제 터미널에서 프로그램을 다시 컴파일합니다.

javac DuplicateCheck.java

컴파일이 성공하면 프로그램을 실행합니다.

java DuplicateCheck

다음과 유사한 출력이 표시되어야 합니다.

Original List: [Alice, Bob, Alice, Charlie, Bob, David]
Size of Original List: 6
Set created from List: [Alice, Bob, Charlie, David]
Size of Set: 4
Number of duplicates (excluding first occurrence): 2

원래 목록의 크기는 6 이지만, 여기서 생성된 HashSet의 크기는 4 입니다. 차이 (6 - 4 = 2) 는 두 개의 중복된 이름 ("Alice"와 "Bob"이 각각 첫 번째 발생 이후 한 번씩 나타남) 이 있었음을 정확하게 나타냅니다.

이것은 HashSet을 사용하여 컬렉션에서 고유한 요소의 수 또는 중복된 요소의 수를 얼마나 쉽게 찾을 수 있는지 보여줍니다.

Null 요소로 테스트

이전 단계에서는 HashSet이 중복된 null 이 아닌 요소를 처리하는 방법을 살펴보았습니다. 이제 HashSetnull 요소를 추가하려고 할 때 어떻게 동작하는지 살펴보겠습니다. 컬렉션이 null을 처리하는 방식을 이해하는 것은 중요합니다. 신중하게 처리하지 않으면 예상치 못한 동작이나 오류가 발생할 수 있기 때문입니다.

HashSet은 하나의 null 요소를 허용합니다. null을 여러 번 추가하려고 하면 첫 번째 null만 저장됩니다.

이를 테스트하기 위해 DuplicateCheck.java 프로그램을 다시 한 번 수정해 보겠습니다.

WebIDE 코드 편집기에서 DuplicateCheck.java 파일을 엽니다.

main 메서드를 수정하여 목록에 null 값을 포함합니다.

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

public class DuplicateCheck {

    public static void main(String[] args) {
        // Create a list with some duplicate and null elements
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add(null); // Add null
        names.add("Alice"); // Duplicate
        names.add("Charlie");
        names.add(null); // Add null again
        names.add("Bob"); // Duplicate
        names.add("David");
        names.add(null); // Add null a third time

        System.out.println("Original List: " + names);
        System.out.println("Size of Original List: " + names.size());

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

        System.out.println("Set created from List: " + uniqueNamesSet);
        System.out.println("Size of Set: " + uniqueNamesSet.size());

        // The difference in size tells us how many duplicates were removed
        // Note: This calculation is less straightforward with nulls and duplicates combined
        // int duplicatesCount = names.size() - uniqueNamesSet.size();
        // System.out.println("Number of duplicates (excluding first occurrence): " + duplicatesCount);
    }
}

여기서는 nullnames 목록에 여러 번 추가했습니다. 또한 null이 포함될 때 중복 계산이 덜 의미가 있고, null을 사용한 집합의 동작에 집중하고 있기 때문에 중복 수 계산을 주석 처리했습니다.

수정된 DuplicateCheck.java 파일을 저장합니다.

터미널에서 프로그램을 컴파일합니다.

javac DuplicateCheck.java

컴파일이 성공하면 프로그램을 실행합니다.

java DuplicateCheck

다음과 유사한 출력이 표시되어야 합니다.

Original List: [Alice, Bob, null, Alice, Charlie, null, Bob, David, null]
Size of Original List: 9
Set created from List: [null, Alice, Bob, Charlie, David]
Size of Set: 5

출력을 관찰합니다.

  • Original List는 여러 개의 null 값을 포함하여 모든 요소를 표시합니다. 크기는 9 입니다.
  • Set created from List는 고유한 요소만 포함합니다. null이 목록에 여러 번 추가되었음에도 불구하고 집합에 한 번만 나타나는 것을 확인하세요. 집합의 크기는 5(Alice, Bob, Charlie, David 및 null) 입니다.

이는 HashSet이 하나의 null 요소를 허용하고, 후속 null 추가를 다른 요소와 마찬가지로 중복으로 처리함을 확인합니다.

이제 HashSetnull 요소를 처리하는 방식을 성공적으로 테스트했습니다. 이것으로 중복 확인을 위해 HashSet을 사용하고 고유 및 null 요소에 대한 동작을 이해하는 탐구를 마칩니다.

요약

이 랩에서는 HashSet을 사용하여 Java 컬렉션 내에서 중복 요소를 효율적으로 확인하는 방법을 배웠습니다. 중복 요소가 있는 List를 생성한 다음, 각 요소를 HashSet에 추가하려고 시도하면서 반복했습니다. 요소가 이미 존재하는 경우 false를 반환하는 add() 메서드의 반환 값을 확인하여 중복 요소를 식별하고 별도의 HashSet에 수집할 수 있었습니다. 이 방법은 효과적인 중복 감지를 위해 HashSet의 고유 요소 속성 및 빠른 조회 기능을 활용합니다.