2017-05-17 1 views
5

Ich habe die Datenstruktur MyPojo genannt, die Felder hat, die time, name und timetaken genannt werden (alle sind in Strings). Ich versuche, einige Gruppierung zu tun, wie folgt:Java 8 sammeln und ändern Sie das Format des Ergebnisses

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

Bitte beachten Sie, dass ich eine Methode habe getTimeTakenAsDouble genannt timetaken String doppelten Wert zu konvertieren.

Daraus ergibt sich wie folgt:

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

jedoch die Daten entweder in folgendem Format mein Frontend Entwickler wollte: zu

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

oder

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

Ich denke, Führen Sie Iterationen auf dem resultMap durch und bereiten Sie das 2. Format vor. Ich versuche, die Iteration erneut auf der resultMap durchzuführen. Gibt es einen anderen Weg, damit umzugehen?

Antwort

4

Eigentlich ist es ziemlich interessant, was Sie erreichen wollen. Es ist, als ob Sie versuchen, eine Art von logischen padding zu tun. Die Art, wie ich es gemacht habe, ist Collectors.collectingAndThen zu verwenden. Sobald das Ergebnis da ist - tu ich es einfach mit den benötigten Daten auf.

Beachten Sie, dass ich Sets.difference von guava verwende, aber das kann leicht in eine statische Methode versetzt werden. Außerdem werden zusätzliche Operationen ausgeführt.

Also gehe ich davon aus Ihre MyPojo wie folgt aussieht:

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

und Eingabedaten, die ich überprüft habe gegen ist:

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

Hier ist der Code, der tut, was Sie wollen:

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

Ergebnis davon wäre:

{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

Was ist 'distinctYears' hier? –

+1

@VimalrajSelvam mein schlechtes. gerade hinzugefügt – Eugene

+0

Dies ist ein guter Ansatz. Aber wenn ich das tun musste, habe ich es umgekehrt gemacht: Ich habe zuerst eine Karte erstellt und sie mit allen * zero * Einträgen für jede mögliche Gruppe gefüllt und dann einen Collector benutzt (entweder 'groupingBy' oder' toMap ') mit einem benutzerdefinierten Kartenlieferanten'() -> myMapWithZeroes'. –

Verwandte Themen