Java 에서 리스트가 다른 리스트의 모든 요소를 포함하는지 확인하는 방법

JavaBeginner
지금 연습하기

소개

이 랩에서는 Java 에서 한 리스트가 다른 리스트의 모든 요소를 포함하는지 확인하는 방법을 배우게 됩니다. 이는 컬렉션으로 작업하고 데이터 세트 간의 관계를 이해하는 데 있어 기본적인 작업입니다.

빠른 부분 집합 확인을 위해 Java Collections 프레임워크에서 제공하는 효율적인 containsAll() 메서드를 살펴볼 것입니다. 이해를 굳건히 하기 위해 루프를 사용하여 이 검사를 수동으로 수행하는 방법도 배우게 됩니다. 마지막으로, 빈 리스트와 null 리스트를 포함한 엣지 케이스 (edge cases) 로 이러한 메서드의 동작을 테스트하여 견고한 코드를 보장할 것입니다.

containsAll() 을 사용하여 부분 집합 확인

이 단계에서는 Java 에서 containsAll() 메서드를 사용하여 한 리스트가 다른 리스트의 부분 집합인지 확인하는 방법을 살펴보겠습니다. 이는 컬렉션으로 작업할 때 흔히 사용되는 작업이며, containsAll()은 이 검사를 수행하는 편리한 방법을 제공합니다.

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

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

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubset = mainList.containsAll(subList);

        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList? " + isSubset);

        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList
        boolean isAnotherSubset = mainList.containsAll(anotherList);

        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList? " + isAnotherSubset);
    }
}

코드를 분석해 보겠습니다.

  • 리스트로 작업하기 위해 java.util 패키지에서 ArrayListList를 가져옵니다.
  • mainListsubList의 두 개의 ArrayList 객체를 생성합니다.
  • 두 리스트에 문자열 요소를 추가합니다.
  • 핵심 부분은 mainList.containsAll(subList)입니다. 이 메서드는 mainListsubList에 있는 모든 요소를 포함하는지 확인합니다. 포함하는 경우 true를 반환하고, 그렇지 않으면 false를 반환합니다.
  • 결과를 부울 변수 isSubset에 저장하고 출력합니다.
  • 그런 다음 mainList에 없는 요소를 포함하는 anotherList를 생성하고, 부분 집합이 아닌 경우의 결과를 확인하기 위해 동일한 검사를 수행합니다.

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

이제 WebIDE 하단의 터미널을 엽니다. ~/project 디렉토리에 있는지 확인합니다. 그렇지 않은 경우 cd ~/project 명령을 사용합니다.

javac 명령을 사용하여 Java 코드를 컴파일합니다.

javac SubsetCheck.java

컴파일 오류가 없으면 ~/project 디렉토리에 SubsetCheck.class 파일이 생성된 것을 볼 수 있습니다.

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

java SubsetCheck

다음과 유사한 출력을 볼 수 있습니다.

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList? false

이 출력은 subList의 모든 요소가 mainList에 있기 때문에 실제로 subListmainList의 부분 집합임을 확인하는 반면, "Grape"가 mainList에 없기 때문에 anotherList는 부분 집합이 아닙니다.

수동 루프로 검증

이전 단계에서는 부분 집합을 확인하기 위해 편리한 containsAll() 메서드를 사용했습니다. containsAll()은 효율적이지만, 루프를 사용하여 이 검사를 수동으로 수행하는 방법을 이해하는 것이 도움이 됩니다. 이렇게 하면 컬렉션 메서드가 내부적으로 어떻게 작동하는지 더 깊이 이해할 수 있습니다.

SubsetCheck.java 파일에 부분 집합 검사를 수동으로 수행하는 새 메서드를 추가해 보겠습니다. WebIDE 편집기에서 ~/project/SubsetCheck.java를 엽니다.

main 메서드 외부의 SubsetCheck 클래스 내부에 다음 메서드를 추가합니다.

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }

이 새로운 메서드 isSubsetManual은 두 개의 리스트를 입력으로 받습니다. 그런 다음 subList의 각 element를 반복합니다. 루프 내에서 contains() 메서드를 사용하여 mainList가 현재 element를 포함하는지 확인합니다. subList에서 mainList없는 요소가 하나라도 발견되면, 즉시 subList가 부분 집합이 아니고 false를 반환합니다. 루프가 subList에서 mainList에 없는 요소를 찾지 않고 완료되면 모든 요소가 존재한다는 의미이며, 메서드는 true를 반환합니다.

이제 main 메서드에서 이 새 메서드를 호출하여 결과를 containsAll()과 비교해 보겠습니다. SubsetCheck.javamain 메서드를 수정하여 isSubsetManual에 대한 호출을 포함합니다.

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubsetContainsAll = mainList.containsAll(subList);
        // Check if subList is a subset of mainList using manual loop
        boolean isSubsetManualCheck = isSubsetManual(mainList, subList);


        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList (containsAll)? " + isSubsetContainsAll);
        System.out.println("Is subList a subset of mainList (manual check)? " + isSubsetManualCheck);


        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList using containsAll()
        boolean isAnotherSubsetContainsAll = mainList.containsAll(anotherList);
         // Check if anotherList is a subset of mainList using manual loop
        boolean isAnotherSubsetManualCheck = isSubsetManual(mainList, anotherList);


        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList (containsAll)? " + isAnotherSubsetContainsAll);
        System.out.println("Is anotherList a subset of mainList (manual check)? " + isAnotherSubsetManualCheck);

    }

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }
}

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

이제 터미널에서 업데이트된 코드를 컴파일합니다.

javac SubsetCheck.java

그리고 프로그램을 다시 실행합니다.

java SubsetCheck

containsAll() 메서드와 수동 루프 메서드 모두 동일한 결과를 생성하는 것을 보여주는 다음과 유사한 출력을 볼 수 있습니다.

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList (containsAll)? true
Is subList a subset of mainList (manual check)? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList (containsAll)? false
Is anotherList a subset of mainList (manual check)? false

이 단계는 잠재적인 부분 집합을 반복하고 각 요소가 주 리스트에 있는지 확인하여 containsAll()과 동일한 결과를 얻을 수 있음을 보여줍니다. containsAll()은 일반적으로 간결함과 Java 라이브러리에서 잠재적인 성능 최적화로 인해 선호되지만, 수동 접근 방식을 이해하는 것은 학습에 가치가 있습니다.

빈 리스트 및 Null 리스트로 테스트

이 단계에서는 containsAll() 메서드와 수동 검사 메서드가 빈 리스트와 null 값을 처리할 때 어떻게 동작하는지 살펴보겠습니다. 이러한 예외적인 경우를 이해하는 것은 견고한 코드를 작성하는 데 중요합니다.

WebIDE 편집기에서 ~/project/SubsetCheck.java 파일을 엽니다. main 메서드에 더 많은 테스트 케이스를 추가할 것입니다.

main 메서드를 수정하여 빈 리스트와 null 리스트로 검사를 포함합니다.

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubsetContainsAll = mainList.containsAll(subList);
        // Check if subList is a subset of mainList using manual loop
        boolean isSubsetManualCheck = isSubsetManual(mainList, subList);


        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList (containsAll)? " + isSubsetContainsAll);
        System.out.println("Is subList a subset of mainList (manual check)? " + isSubsetManualCheck);


        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList using containsAll()
        boolean isAnotherSubsetContainsAll = mainList.containsAll(anotherList);
         // Check if anotherList is a subset of mainList using manual loop
        boolean isAnotherSubsetManualCheck = isSubsetManual(mainList, anotherList);


        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList (containsAll)? " + isAnotherSubsetContainsAll);
        System.out.println("Is anotherList a subset of mainList (manual check)? " + isAnotherSubsetManualCheck);

        // --- Test with Empty Lists ---

        // Create an empty list
        List<String> emptyList = new ArrayList<>();

        // Check if emptyList is a subset of mainList
        boolean isEmptySubsetContainsAll = mainList.containsAll(emptyList);
        boolean isEmptySubsetManualCheck = isSubsetManual(mainList, emptyList);

        System.out.println("\nEmpty List: " + emptyList);
        System.out.println("Is emptyList a subset of mainList (containsAll)? " + isEmptySubsetContainsAll);
        System.out.println("Is emptyList a subset of mainList (manual check)? " + isEmptySubsetManualCheck);

        // Check if mainList is a subset of emptyList (should be false unless mainList is also empty)
        boolean isMainSubsetEmptyContainsAll = emptyList.containsAll(mainList);
        boolean isMainSubsetEmptyManualCheck = isSubsetManual(emptyList, mainList);

        System.out.println("Is mainList a subset of emptyList (containsAll)? " + isMainSubsetEmptyContainsAll);
        System.out.println("Is mainList a subset of emptyList (manual check)? " + isMainSubsetEmptyManualCheck);

        // --- Test with Null List ---

        // Create a null list
        List<String> nullList = null;

        // Check with nullList using containsAll()
        System.out.println("\nNull List: " + nullList);
        try {
            boolean isNullSubsetContainsAll = mainList.containsAll(nullList);
            System.out.println("Is nullList a subset of mainList (containsAll)? " + isNullSubsetContainsAll);
        } catch (NullPointerException e) {
            System.out.println("Checking with nullList using containsAll() resulted in: " + e);
        }

        // Check with nullList using manual loop
         try {
            boolean isNullSubsetManualCheck = isSubsetManual(mainList, nullList);
            System.out.println("Is nullList a subset of mainList (manual check)? " + isNullSubsetManualCheck);
        } catch (NullPointerException e) {
            System.out.println("Checking with nullList using manual check resulted in: " + e);
        }
    }

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Add a check for null subList in the manual method
        if (subList == null) {
             throw new NullPointerException("Sub list cannot be null for manual check.");
        }
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }
}

emptyListnullList로 테스트하는 섹션을 추가했습니다. nullList 테스트의 경우, try-catch 블록으로 호출을 묶었습니다. 이는 null 객체에 대해 메서드를 호출하려고 하면 (mainList.containsAll(nullList)와 같이) NullPointerException이 발생하기 때문입니다. 수동 메서드도 subListnull인 경우를 처리해야 하므로 isSubsetManual의 시작 부분에 검사를 추가했습니다.

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

터미널에서 업데이트된 코드를 컴파일합니다.

javac SubsetCheck.java

그리고 프로그램을 다시 실행합니다.

java SubsetCheck

다음과 유사한 출력을 볼 수 있습니다.

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList (containsAll)? true
Is subList a subset of mainList (manual check)? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList (containsAll)? false
Is anotherList a subset of mainList (manual check)? false

Empty List: []
Is emptyList a subset of mainList (containsAll)? true
Is emptyList a subset of mainList (manual check)? true
Is mainList a subset of emptyList (containsAll)? false
Is mainList a subset of emptyList (manual check)? false

Null List: null
Checking with nullList using containsAll() resulted in: java.lang.NullPointerException
Checking with nullList using manual check resulted in: java.lang.NullPointerException: Sub list cannot be null for manual check.

출력에서 다음을 관찰합니다.

  • 빈 리스트는 모든 리스트 (다른 빈 리스트 포함) 의 부분 집합으로 간주됩니다. containsAll()과 수동 메서드 모두 이를 올바르게 식별합니다.
  • 비어 있지 않은 리스트는 빈 리스트의 부분 집합이 아닙니다.
  • null 리스트를 containsAll() 또는 수동 메서드에 전달하면 (null 검사 없이) NullPointerException이 발생합니다. 이는 코드에서 잠재적인 null 값을 처리하는 것의 중요성을 강조합니다.

이 단계는 Java 리스트에서 부분 집합을 확인하는 탐구를 마무리합니다. 내장된 containsAll() 메서드를 사용하는 방법, 수동으로 검사를 수행하는 방법, 그리고 이러한 메서드가 빈 리스트 및 null 리스트에서 어떻게 동작하는지 배웠습니다.

요약

이 Lab 에서는 Java 에서 한 리스트가 다른 리스트의 모든 요소를 포함하는지 확인하는 방법을 배웠습니다. 우리는 주로 Collection 인터페이스에서 제공하는 편리한 containsAll() 메서드를 사용하는 데 중점을 두었습니다.

예제 리스트를 사용하여 containsAll()을 사용하는 방법을 시연하고 부분 집합 및 비부분 집합 사례 모두에 대한 동작을 관찰했습니다. 이 메서드는 이 일반적인 리스트 비교 작업을 수행하는 간결하고 효율적인 방법을 제공합니다.