2017-05-17 16 views
5

Mam strukturę danych o nazwie MyPojo, która ma pola o nazwach time, name i timetaken (wszystkie są w ciągach). Próbuję zrobić grupowanie następująco:Java 8 odbierz i zmień format wyniku.

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)))); 

Należy pamiętać, że mam metodę o nazwie getTimeTakenAsDouble przekonwertować ciąg timetaken do podwójnej wartości.

Wynika to w sposób następujący:

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

Jednak moja frontend developer chciał albo dane w następującym formacie:

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

lub

[ 
      { 
        "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 
      } 
    ] 

Zastanawiam się wykonaj iteracje na resultMap i przygotuj drugi format. Próbuję ponownie wykonać iterację na resultMap. Czy jest jakaś inna metoda radzenia sobie z tym?

Odpowiedz

4

Właściwie to całkiem interesujące, co próbujesz osiągnąć. To tak, jak próbujesz zrobić coś w rodzaju logicznego padding. Sposób, w jaki to zrobiłem, to użycie Collectors.collectingAndThen. Gdy wynik już istnieje - po prostu podkładam go potrzebnym danym.

Należy zauważyć, że używam Sets.difference z guava, ale można to łatwo umieścić w metodzie statycznej. Są również wykonywane dodatkowe operacje.

Więc zakładamy MyPojo wygląda następująco:

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()); 
    } 
} 

I dane wejściowe, że mam porównywane jest:

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")); 

Oto kod, który robi to, co chcesz:

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; 
          } 
        ))); 

Wynik tego będzie:

{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

Co to jest "distinctYears"? –

+1

@VimalrajSelvam my bad. Właśnie dodano – Eugene

+0

To jest dobre podejście. Chociaż kiedy musiałem to zrobić, zrobiłem to na odwrót: najpierw utworzyłem mapę i wypełniłem ją wszystkimi * zerowymi * wpisami dla każdej możliwej grupy, a następnie użyłem kolektora (albo "groupingBy" lub "toMap"). ') z niestandardowym dostawcą map'() -> myMapWithZeroes'. –