2016-03-28 8 views
5

私はPersonオブジェクトのコレクションを持っています。ストリームとコレクタを使用するコレクションのサブリストエントリへのJava 8のマッピング

public class Person { 

    String name; 

    ChildrenListHolder childrenListHolder; 
} 

public class ChildrenListHolder { 
    List<Children> children; 
} 

public class Children { 
    String childrensName; 
} 

(実体構造が第三者によって与えられている。)

さて、私はMap<String,List<Person>> childrensName必要 - (簡体字)例えば>人物リストに

を:

Person father: {name: "John", childrensListHolder -> {"Lisa", "Jimmy"}} 
Person mother: {name: "Clara", childrensListHolder -> {"Lisa", "Paul"}} 
Person george: {name: "George", childrensListHold -> "Paul"}} 

地図が必要です

Map<String, List<Person>> map: {"Lisa" -> {father, mother}, 
           "Jimmy" -> {father}, 
           "Paul" -> {mother, george}} 

私はそれを忘れずに行うことができます。しかし、私はストリームとコレクターを使ってこれをどうやって行うことができますか?私は多くのアプローチを試みましたが、私は期待される結果を得ることができません。 TIA。 List<Person> persons考える

答えて

7

は、あなたはこれが人々の上にストリームを作成して、次の

Map<String,List<Person>> map = 
    persons.stream() 
      .flatMap(p -> p.childrenListHolder.children.stream().map(c -> new AbstractMap.SimpleEntry<>(c, p))) 
      .collect(Collectors.groupingBy(
      e -> e.getKey().childrensName, 
      Collectors.mapping(Map.Entry::getValue, Collectors.toList()) 
      )); 

を持つことができます。次に、それぞれの人物は、各子供のために子供と人物を保持するタプルによってフラット・マッピングされる。最後に、子の名前でグループ化し、すべての人物をリストにまとめます。

サンプルコードの適切なコンストラクタがあると仮定:

public static void main(String[] args) { 
    List<Person> persons = Arrays.asList(
     new Person("John", new ChildrenListHolder(Arrays.asList(new Children("Lisa"), new Children("Jimmy")))), 
     new Person("Clara", new ChildrenListHolder(Arrays.asList(new Children("Lisa"), new Children("Paul")))), 
     new Person("George", new ChildrenListHolder(Arrays.asList(new Children("Paul")))) 
    ); 

    Map<String,List<Person>> map = 
     persons.stream() 
       .flatMap(p -> p.childrenListHolder.children.stream().map(c -> new AbstractMap.SimpleEntry<>(c, p))) 
       .collect(Collectors.groupingBy(
       e -> e.getKey().childrensName, 
       Collectors.mapping(Map.Entry::getValue, Collectors.toList()) 
       )); 

    System.out.println(map); 
} 
+0

ありがとうございました。残念ながら、それは動作しません。 flatMap呼び出しは 'Stream 'を返すので、 'e.getKey'を使った収集は機能しません。 – t777

+1

@ t777 Hmm私はEclipse Mars.2の中でそのコードを実行しました。どのIDEを使用していますか? – Tunaki

+0

私はEclipse Luna 2(4.4.2) – t777

5

私はのためにとのifの束とそれを行うことができます。

私はあなたがストリーム/コレクター・ソリューションを求めていることを知っているが、いずれにしてもMap#computeIfAbsentを使用してループのネストされたが、あまりにも正常に動作します:

Map<String, List<Person>> map = new HashMap<>(); 
for(Person p : persons) { 
    for(Children c : p.childrenListHolder.children) { 
     map.computeIfAbsent(c.childrensName, k -> new ArrayList<>()).add(p); 
    } 
} 

と、これはコレクションに導入された新しいforEachメソッドを使用して書かれました:もちろん

Map<String, List<Person>> map = new HashMap<>(); 
persons.forEach(p -> p.childrenListHolder.children.forEach(c -> map.computeIfAbsent(c.childrensName, k -> new ArrayList<>()).add(p))); 

それはワンライナーもTunakiのソリューション(1)のように簡単に並列化ではありませんが、あなたはあまりにも(とよということを達成するためだ場合の「束」を必要としませんテンポラリマップエントリインスタンスの作成も避けてください)。

+2

はい、これも素晴らしい解決策です。利点は、あなたが子供と人を保持するためのタプルを持つ必要はないということです。 – Tunaki

+0

ありがとうございます。私はあなたのソリューションも好きです。私は2つの答えを受け入れることができました。 ;) – t777

関連する問題