2017-01-09 1 views
4

나는 하나의 객체
에 모든 중복 항목을 병합하여 중복을 가질 수 목록에서 고유 한 친구 목록을 생성해야 - 친구는 다른 소셜 피드 페치 1에 넣어 큰 목록
1. 친구 - [이름 : "Johnny Depp", dob : "1970-11-10", 출처 : "FB", fbAttribute : ".."]
2. 친구 - [이름 : "Christian 012. [Bale], dob : "1970-01-01", 출처 : "LI", liAttribute : ".."]
3. 친구 - [이름 : "Johnny Depp", dob : "1970-11-10" 출처 : "Twitter", twitterAttribute : ".."]
4. 친구 - [이름 : "Johnny Depp", dob : "1970-11 10. "출처 :"LinkedIn ", liAttribute :".. "]
5. 친구 - [이름 :"Christian Bale ", dob :"1970-01-01 ", 출처 :"LI ", liAttribute : .. "]
자바 스트림 병합 또는 감소 중복 된 개체를

예상 출력
1. 친구 - [이름 :"크리스찬 베일 ", 생년월일 :"1970-01-01 ", liAttribute :".. ", fbAttribute :".. " , twitterAttribute : ".."]
2. 친구 - [이름 : "Johnny Depp", dob : "1970-11-10", liAttribute : "..", fbAttribute : "..", twitterAttribute : ". "]

질문 - 우리 없이는 어떻게 병합 할 수 있습니까? 어떤 중간 컨테이너를 보내고 있습니까? 나는 중간지도를 쉽게 사용할 수 있고 엔트리의 각 값에 대해 reduce를 적용 할 수있다.

List<Friend> friends; 
Map<String, List<Friend>> uniqueFriendMap 
    = friends.stream().groupingBy(Friend::uniqueFunction); 
List<Friend> mergedFriends = uniqueFriendMap.entrySet() 
    .stream() 
    .map(entry -> { 
      return entry.getValue() 
       .stream() 
       .reduce((a,b) -> friendMergeFunction(a,b)); 
    }) 
    .filter(mergedPlace -> mergedPlace.isPresent()) 
    .collect(Collectors.toList()); 

나는 중간지도 uniqueFriendMap를 사용하지 않고이 일을 좋아한다. 어떤 제안?

답변

5

groupingBy 조작 (또는 이와 유사한)은 피할 수 없으며 조작으로 작성된 Map은 그룹 키를 찾고 중복을 찾는 조작 중에도 사용됩니다. 그러나이를 그룹 요소의 축소와 결합 할 수 있습니다.

Map<String, Friend> uniqueFriendMap = friends.stream() 
    .collect(Collectors.groupingBy(Friend::uniqueFunction, 
     Collectors.collectingAndThen(
      Collectors.reducing((a,b) -> friendMergeFunction(a,b)), Optional::get))); 

지도의 값은 이미 결과로 나오는 고유 한 친구입니다. 당신이 정말 List 필요한 경우 일반 컬렉션 작업로를 만들 수 있습니다

List<Friend> mergedFriends = new ArrayList<>(uniqueFriendMap.values()); 

이 두 번째 작업이 여전히 당신을 귀찮게하는 경우, 당신은 collect 작업에서 숨길 수 :

List<Friend> mergedFriends = friends.stream() 
    .collect(Collectors.collectingAndThen(
     Collectors.groupingBy(Friend::uniqueFunction, Collectors.collectingAndThen(
      Collectors.reducing((a,b) -> friendMergeFunction(a,b)), Optional::get)), 
     m -> new ArrayList<>(m.values()))); 

그러나 원래의 접근 방식에서도 몇 가지 단순화가 가능합니다. Map 값만 처리하는 경우 entrySet()을 사용할 필요가 없으므로 각 항목에 getValue()으로 전화해야합니다. 처음에는 values()을 처리 할 수 ​​있습니다. 그런 다음 구문을 사용하지 않아도됩니다. input -> expression이면 충분합니다. 이전 그룹화 조작의 그룹은 비워 둘 수 없으므로 필터 단계는 더 이상 사용되지 않습니다. 따라서 원래의 접근 방식은 다음과 같습니다.

Map<String, List<Friend>> uniqueFriendMap 
    = friends.stream().collect(Collectors.groupingBy(Friend::uniqueFunction)); 
List<Friend> mergedFriends = uniqueFriendMap.values().stream() 
    .map(group -> group.stream().reduce((a,b) -> friendMergeFunction(a,b)).get()) 
    .collect(Collectors.toList()); 

별로 나쁘지 않습니다.위에서 말했듯이, 융합 된 작업은 피할 수없는 것처럼 생성을 건너 뛰지 않습니다 (Map). 각 그룹을 대표하는 List의 생성물 만 건너 뜁니다. 즉, 단일 그룹 Friend으로 줄입니다.

+1

안녕하세요. Holger 님, 아마도 'Collectors.groupingBy'를'Collectors.toMap'과 같이 'Map uniqueFriendMap = friends.stream(). collect (Collectors.toMap (Friend :: uniqueFunction, Function.identity(), this :: friendMergeFunction))', 훨씬 더 간단하다고 생각하지 않습니까? –

2

그냥 방법 Collectors.frequency을 사용하십시오.

+4

어쩌면 내가 뭔가를 놓치고 있지만 이것이 도움이 될지 모르겠습니다. 각 중복 객체에서 각 속성 값을 읽음으로써 빈도를 사용하여 중복 객체를 1 객체로 어떻게 줄일 수 있는지 자세히 설명해 주시겠습니까? 위의 예를 통해 설명 할 수 있습니까? – Vku