2016-09-23 5 views
1

私は、対応する結果がCollector.groupingBy(Function, groupingBy(classifier, toList())マルチレベルマップは、()(コレクト)groupingBy()と還元()

Map<String, Map<Person.Sex, List<Person>>> groupByYearThenSex = personList.stream().collect(
    groupingBy(p ->{ 
      if(p.getYear() > 2015) return "New members"; 
      else if(p.getYear() < 2009) return "Senior members"; 
      else return "Normal members"; 
     }, 
     groupingBy(Person::getSex) 
    ) 
); 
groupByYearThenSex.forEach((String y, Map<Person.Sex, List<Person>> m) ->{ 
    System.out.println("\n" + y); 
    m.forEach((Person.Sex s, List<Person> p) -> { 
     System.out.println(" " + s); 
     p.forEach((Person prsn) -> { 
      System.out.println("  " + prsn.toString()); 
     }); 

    }); 
}); 

を書くために管理:

New members 

     MALE 
      Person{name: Gawel, age: 23, sex: MALE} 

Normal members 

     MALE 
      Person{name: Patryk, age: 34, sex: MALE} 
      Person{name: Pawel, age: 21, sex: MALE} 
      Person{name: Bolek, age: 12, sex: MALE} 
      Person{name: Lolek, age: 12, sex: MALE} 
     FEMALE 
      Person{name: Jola, age: 70, sex: FEMALE} 
      Person{name: Ala, age: 25, sex: FEMALE} 

Senior members 

     FEMALE 
      Person{name: Iwona, age: 34, sex: FEMALE} 
      Person{name: Oliwia, age: 17, sex: FEMALE} 

今、私がしようとしています次のように最も古いメンバーだけを一覧表示するマルチレベルマップを作成します。

New members 

     MALE 
      Person{name: Gawel, age: 23, sex: MALE} 

Normal members 

     MALE 
      Person{name: Patryk, age: 34, sex: MALE} 
     FEMALE 
      Person{name: Jola, age: 70, sex: FEMALE} 

Senior members 

     FEMALE 
      Person{name: Iwona, age: 34, sex: FEMALE} 

以下のコードは機能しません。私は、変数RRは私がFunction<R,RR> =>collectingAndThen(reducing(), Optional)を考えている互換性のない境界エラーを、持っている推論」を取得。私は最も古いものを得るために人の流れを削減し、?

Map<String, Map<Person.Sex, List<Person>>> groupByYearThenSexOldest = personList.stream().collect(
    groupingBy(p ->{ 
      if(p.getYear() > 2015) return "New members"; 
      else if(p.getYear() < 2009) return "Senior members"; 
      else return "Normal members"; 
     }, 
     groupingBy(Person::getSex, collectingAndThen(
      reducing((p1, p2) -> p1.getAge() > p2.getAge() ? p1 : p2), 
      Optional::get) 
     ) 
    ) 
); 

答えて

0

上記の出力を得ることができますどのような方法があります。。問題は、リストを縮小しているので、それはあなたの代わりにMap<String, Map<Person.Sex, List<Person>>>Map<String, Map<Person.Sex, Person>>を与える必要があり、マップの型パラメータである

しかし、あなたはmaxBycollectingAndThenで二groupingByコレクターを組み合わせることができます。

groupingBy(Person::getSex, collectingAndThen(maxBy(Comparator.comparingInt(Person::getAge)), Optional::get) 

複数のフィールドでグループ化する必要がある場合は、フィールドをグループ化するリストを使用できます(適切なequalsメソッドとhashcodeメソッドがあると仮定して)。例えば:

与え
Function<Person, String> groupingYear = p -> { 
    if (p.getYear() > 2015) return "New members"; 
    else if (p.getYear() < 2009) return "Senior members"; 
    else return "Normal members"; 
}; 

Map<Object, Optional<Person>> map2 = 
    personList.stream() 
       .collect(groupingBy(p -> Arrays.asList(groupingYear.apply(p), p.getSex()), maxBy(Comparator.comparingInt(Person::getAge)))); 

[Normal members, MALE] => Optional[Person{name='Patryk', age=34, sex=MALE}] 
[Senior members, FEMALE] => Optional[Person{name='Iwona', age=34, sex=FEMALE}] 
[Normal members, FEMALE] => Optional[Person{name='Jola', age=70, sex=FEMALE}] 
[New members, MALE] => Optional[Person{name='Gawel', age=23, sex=MALE}] 

をしかし、その後、あなたがtoMapコレクタを使用して開始し、2つの値が一緒にグループ化されたときにユーザーが指定するマージ機能で年齢を比較することができる:

Map<Object, Person> map = 
    personList.stream() 
       .collect(toMap(p -> Arrays.asList(groupingYear.apply(p), p.getSex()), 
          p -> p, 
          (p1, p2) -> { 
           if(p1.getAge() > p2.getAge()) return p1; 
           else return p2; 
          }, 
          HashMap::new)); 

MapにはObjectがキーとして含まれています(実際のタイプは非常に長く書いています)が、あなたは献辞を作成することができますdクラスMemberStatusAndSexは、両方の属性(Listの代わりに - このクラスにequalsとhashcodeを実装することを忘れないでください)を組み合わせ、最後にMap<MemberStatusAndSex, Person>を取得します。