Java/스트림(Stream)

[Java]Stream 중복 제거하는 방법 - distinct 메서드

DevStory 2022. 8. 26.

dictinct 메서드

Stream 클래스에서 제공하는 distinct() 메서드는 중복 요소를 제거하고 고유한 요소로 구성된 Stream을 반환합니다.

Stream<T> distinct();

dictinct 메서드 특징

  • distinct() 메서드는 중복 요소가 없는 고유한 요소로 구성된 새로운 Steram을 반환합니다. 중복된 요소를 확인하기 위해 equals() 메서드와 hashCode() 메서드를 사용합니다.
  • 중복된 요소가 존재하는 경우 첫 번째 위치의 요소를 반환하므로 정렬 순서를 보장합니다.

예제 1. Integer 타입의 정렬된 List

다음 예제는 Integer 타입의 값이 정렬된 List를 스트림으로 변환 후 distinct() 메서드를 호출하여 중복 요소를 제거합니다.

public static void main(String args[]) {
  List<Integer> intList =
          new ArrayList<>(Arrays.asList(10, 10, 20, 20, 20, 30, 30));

  Stream<Integer> intStream = intList.stream().distinct();

  intStream.forEach(System.out::println);
}

[실행 결과]

10
20
30

distinct() 메서드 반환 결과를 Stream이 아닌 List로 반환받고 싶다면, distinct() 메서드 뒤에 Collectors.toList()를 매개변수로 가지는 collect() 메서드를 호출합니다.

 

다음 예제는 distinct() 메서드 반환 결과를 List로 변환합니다.

public static void main(String args[]) {
  List<Integer> intList =
          new ArrayList<>(Arrays.asList(10, 10, 20, 20, 20, 30, 30));

  List<Integer> intStreamToList = 
          intList.stream().distinct().collect(Collectors.toList());

  intStreamToList.forEach(System.out::println);
}

[실행 결과]

10
20
30

예제 2. Integer 타입의 정렬되지 않은 List

다음 예제는 Integer 타입의 값이 정렬되지 않은 List를 스트림으로 변환 후 distinct() 메서드를 호출하여 중복 요소를 제거합니다.

public static void main(String args[]) {
  List<Integer> intList =
          new ArrayList<>(Arrays.asList(40, 10, 30, 20, 10, 30, 20, 40));

  List<Integer> intStreamToList =
          intList.stream().distinct().collect(Collectors.toList());

  intStreamToList.forEach(System.out::println);
}

[실행 결과]

40
10
30
20

중복된 요소가 존재하는 경우 첫 번째 위치에 존재하는 요소가 반환되는 것을 확인할 수 있습니다.


예제 3. 사용자가 정의한 클래스인 경우

다음 예제는 사용자가 정의한 클래스 Person 타입의 List를 스트림으로 변환 후 distinct() 메서드를 호출합니다.

 

[Person 클래스]

public class Person {
  private String Name;
  private Integer Age;

  public Person(String name, Integer age) {
    Name = name;
    Age = age;
  }

  @Override
  public String toString() {
    return "Person{Name='" + Name + "\', Age=" + Age + "}";
  }
}

[Main문]

public static void main(String args[]) {
  List<Person> intList = new ArrayList<>(Arrays.asList(
          new Person("둘리", 20),
          new Person("둘리", 20),
          new Person("또치", 30),
          new Person("또치", 30)
  ));

  List<Person> intStreamToList =
          intList.stream().distinct().collect(Collectors.toList());

  intStreamToList.forEach(System.out::println);
}

[실행 결과]

Person{Name='둘리', Age=20}
Person{Name='둘리', Age=20}
Person{Name='또치', Age=30}
Person{Name='또치', Age=30}

List의 각 요소는 실제 데이터 값이 아니라 참조값을 가집니다.

 

따라서, 기본 타입이 아닌 참조 타입인 경우 클래스에서 hashCode() 메서드와 equals() 메서드를 재정의합니다.

 

[Person 클래스]

public class Person {
  // ...
  @Override
  public int hashCode() {
    int prime = 31;
    int result = 1;
    result = prime * result + ((Name == null) ? 0 : Name.hashCode());
    result = prime * result + ((Age == null) ? 0 : Age.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    Person other = (Person) obj;
    return Objects.equals(Name, other.Name) && Age == other.Age;
  }
}

[Main문]

public static void main(String args[]) {
  List<Person> personList = new ArrayList<>(Arrays.asList(
          new Person("둘리", 20),
          new Person("둘리", 20),
          new Person("또치", 30),
          new Person("또치", 30)
  ));

  List<Person> personList =
          intList.stream().distinct().collect(Collectors.toList());

  personList.forEach(System.out::println);
}

[실행 결과]

Person{Name='둘리', Age=20}
Person{Name='또치', Age=30}
반응형

댓글