[JAVA8] 중복제거 하기


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Distinct {

 public static void main(String[] args) {

  System.out.println("defaultDistinctWithOnlyString");
  List names = Arrays.asList("aaa", "bbb", "ccc", "ddd", "aaa", "ccc", "aaa", "aaa");
  List distinctList = names.stream().distinct().collect(Collectors.toList());
  distinctList.forEach(System.out::println);

  // result : aaa , bbb, ccc , ddd
  // 다음의 경우에는 기대와는 다른 결과가 나올 수 있다.

  Person p1 = new Person();
  Person p2 = new Person();
  Person p3 = new Person();
  Person p4 = new Person();
  Person p5 = new Person();

  p1.setName("aaa");
  p1.setAge(20);
  p1.setHeight(175);

  p2.setName("bbb");
  p2.setAge(25);
  p2.setHeight(180);

  p3.setName("ccc");
  p3.setAge(26);
  p3.setHeight(185);

  p4.setName("aaa");
  p4.setAge(20);
  p4.setHeight(185);

  p5.setName("bbb");
  p5.setAge(30);
  p5.setHeight(175);

  List people = new ArrayList<>();
  people.add(p1);
  people.add(p2);
  people.add(p3);
  people.add(p4);
  people.add(p5);

  System.out.println("defaultDistinct");
  List defaultDistinct = people.stream().distinct().collect(Collectors.toList());
  defaultDistinct.forEach(System.out::println);

  // Person 객체를 알아서 distinct 를 해줄 것이라고 생각하고 돌려보면 
  // 아래와 같이 아무작업이 되지 않은 데이터가 나온다.

  // Person [name=aaa, age=20, height=175]
  // Person [name=bbb, age=25, height=180]
  // Person [name=ccc, age=26, height=185]
  // Person [name=aaa, age=20, height=175]
  // Person [name=bbb, age=30, height=190]

  // [ distinct ]
  // Returns a stream consisting of the distinct elements (according to
  // Object.equals(Object)) of this stream.

  // 우선 무엇으로 중복을 제거할 것인가에 대한 기준이 없고, 
  // distinct 자체도 equals 메서드를 사용하여 엘리먼트들을 분류하기 때문이다.

  // 아래와 같이 Predicate 를 만들어서 사용하면, 원하는 형태의 값을 얻을 수 있다.

  System.out.println("distinctByName");
  List distinctByName = people.stream().filter(distinctByKey(e -> e.getName()))
    .collect(Collectors.toList());
  distinctByName.forEach(System.out::println);

  // Person [name=aaa, age=20, height=175]
  // Person [name=bbb, age=25, height=180]
  // Person [name=ccc, age=26, height=185]

  System.out.println("distinctByAge");
  List distinctByAge = people.stream().filter(distinctByKey(e -> e.getAge()))
    .collect(Collectors.toList());
  distinctByAge.forEach(System.out::println);

  // Person [name=aaa, age=20, height=175]
  // Person [name=bbb, age=25, height=180]
  // Person [name=ccc, age=26, height=185]
  // Person [name=bbb, age=30, height=190]

  System.out.println("distinctByHeight");
  List distinctByHeight = people.stream().filter(distinctByKey(e -> e.getHeight()))
    .collect(Collectors.toList());
  distinctByHeight.forEach(System.out::println);

  // Person [name=aaa, age=20, height=175]
  // Person [name=bbb, age=25, height=180]
  // Person [name=ccc, age=26, height=185]

 }

 public static  Predicate distinctByKey(Function keyExtractor) {
  Map seen = new ConcurrentHashMap<>();
  return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
 }

}

class Person {

 String name;
 int age;
 int height;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public int getHeight() {
  return height;
 }

 public void setHeight(int height) {
  this.height = height;
 }

 @Override
 public String toString() {
  return "Person [name=" + name + ", age=" + age + ", height=" + height + "]";
 }

}




refs :
http://stackoverflow.com/questions/23699371/java-8-distinct-by-property

댓글

이 블로그의 인기 게시물

[JDBC] 쿼리 후에 ResultSet 에 데이터가 있는지 확인하는 방법

[Android] Android 로깅 시 isLoggable() 메서드 사용

[Spring] @PropertySource and Environment 사용시 Property 값이 null 로 들어오는 경우