2017-01-09 4 views
4

私は例つのオブジェクト
にすべての重複したエントリをマージして、重複を持つことができ、リストから独自の友達リストを生成する必要があります - 友達が異なる社会のフィードからフェッチされ、1に入れますビッグリスト
1.フレンド - [名前: "ジョニーデップ"、dob: "1970-11-10"、出典: "FB"、fbAttribute: ".."]
2.フレンド - [name: "Christian "、"寄稿者: "1970年1月10日"、ドバイ: "1970年 - 01年"、ソース: "LI"、LiAttribute: ".."]
3.友人 - [名前: "ジョニーデップ"ソース: "Twitter"、twitterAttribute: ".."]
4.友達 - [名前: "Johnny Depp"、dob: "1970-11 "名前:" Christian Bale "、dob:" 1970-01-01 "、出典:" LI "、liAttribute:"友達の名前: "リンク先:" LinkedIn "、liAttribute:" .. "]
.. "]
Javaストリームマージまたは重複するオブジェクトを減らす

の予想される出力
1.フレンド - [名: "クリスチャン・ベール"、DOB: "1970-01-01"、liAttribute:" .. "fbAttribute:" ..」 、twitterAttribute: ".."]
2.フレンド - [名前: "ジョニーデップ"、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()); 

この第2の動作はまだあなたを不愉快にさせる場合は、あなたが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の作成をスキップするだけで、1つにまとめて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

関連する問題