2017-05-17 10 views
5

time,nameおよびtimetakenというフィールドを持つMyPojoという名前のデータ構造体があります(すべてが文字列です)。私は次のようにいくつかのグループ分けをやろうとしている:Java 8は、結果のフォーマットを収集し、変更します

List<MyPojo> myPojos = Arrays.asList(
     new MyPojo("2017", "ABC", "30"), 
     new MyPojo("2017", "ABC", "20"), 
     new MyPojo("2016", "ABC", "25"), 
     new MyPojo("2017", "XYZ", "40") 
    ); 

    Map<String, Map<String, Double>> resultMap = myPojos.stream() 
     .collect(Collectors.groupingBy(MyPojo::getName, 
      Collectors.groupingBy(MyPojo::getTime, 
       Collectors.averagingDouble(MyPojo::getTimeTakenAsDouble)))); 

私は方法は、二重の値にtimetaken文字列を変換するgetTimeTakenAsDoubleを呼んでいることに注意してください。

次のようにこれは、結果:

{ABC={2017=25.0, 2016=25.0}, XYZ={2017=40.0}} 

はしかし、私のフロントエンド開発者はデータを望んでいた以下のいずれかの形式で:

{ABC={2017=25.0, 2016=25.0}, XYZ={2017=40.0, 2016=0.0}} 

または

[ 
      { 
        "time": "2017", 
        "name": "ABC", 
        "avgTimeTaken": 25.0 
      }, 
      { 
        "time": "2017", 
        "name": "XYZ", 
        "avgTimeTaken": 40.0 
      }, 
      { 
        "time": "2016", 
        "name": "ABC", 
        "avgTimeTaken": 25.0 
      }, 
      { 
        "time": "2016", 
        "name": "XYZ", 
        "avgTimeTaken": 0.0 
      } 
    ] 

私はに考えていますresultMapで繰り返しを実行し、2番目の形式を準備します。私はresultMapで繰り返しを実行しようとしています。これを処理する他の方法はありますか?

答えて

4

実際、あなたが達成しようとしていることはかなり面白いです。あなたが何らかの論理的なものをしようとしているようです。padding。私がやったやり方はCollectors.collectingAndThenです。結果が表示されたら、必要なデータを入力するだけです。

私はをguavaから使用していますが、これは簡単に静的メソッドに入れることができます。また、追加の操作が実行されます。

だから私はあなたのMyPojoは、次のようになりますと仮定します。私は反対チェックした

static class MyPojo { 

    private final String time; 

    private final String name; 

    private final String timetaken; 

    public MyPojo(String time, String name, String timetaken) { 
     super(); 
     this.name = name; 
     this.time = time; 
     this.timetaken = timetaken; 
    } 

    public String getName() { 
     return name; 
    } 

    public String getTime() { 
     return time; 
    } 

    public String getTimetaken() { 
     return timetaken; 
    } 

    public static double getTimeTakenAsDouble(MyPojo pojo) { 
     return Double.parseDouble(pojo.getTimetaken()); 
    } 
} 

そして、入力データは次のとおりです。ここで

List<MyPojo> myPojos = Arrays.asList(
      new MyPojo("2017", "ABC", "30"), 
      new MyPojo("2017", "ABC", "20"), 
      new MyPojo("2016", "ABC", "25"), 
      new MyPojo("2017", "XYZ", "40"), 
      new MyPojo("2018", "RDF", "80")); 

は何をしたいんコードです:

Set<String> distinctYears = myPojos.stream().map(MyPojo::getTime).collect(Collectors.toSet()); 

Map<String, Map<String, Double>> resultMap = myPojos.stream() 
      .collect(Collectors.groupingBy(MyPojo::getName, 
        Collectors.collectingAndThen(
          Collectors.groupingBy(MyPojo::getTime, 
            Collectors.averagingDouble(MyPojo::getTimeTakenAsDouble)), 
          map -> { 
           Set<String> localYears = map.keySet(); 
           SetView<String> diff = Sets.difference(distinctYears, localYears); 
           Map<String, Double> toReturn = new HashMap<>(localYears.size() + diff.size()); 
           toReturn.putAll(map); 
           diff.stream().forEach(e -> toReturn.put(e, 0.0)); 
           return toReturn; 
          } 
        ))); 

結果は次のようになります。

{ABC={2016=25.0, 2018=0.0, 2017=25.0}, 
RDF={2016=0.0, 2018=80.0, 2017=0.0}, 
XYZ={2016=0.0, 2018=0.0, 2017=40.0}} 
+0

「distinctYears」とは何ですか? –

+1

@VimalrajSelvam私の悪い。ちょうど追加 – Eugene

+0

これは良いアプローチです。これを行う必要があるときには、もう一度やりました:最初にマップを作成し、可能なグループごとにすべての* zero *エントリを入力してから、コレクタを使用しました(groupingByまたはtoMap ')をカスタムマップサプライヤ'() - > myMapWithZeroes'で置き換えます。 –

関連する問題