1
votes

java streams: regroupement et ajout de champs

J'ai un flux de MetricGroup , où:

< MetricGroup("app1", 2, 400) , MetricGroup("app2", 1, 200) >

Je dois résumer toutes les métriques d'application. Je veux dire, pour chaque application ( MetricGroup.application ), je dois ajouter tous les metric.uploadedDocs dans une métrique sumMetric.uploadedDocs et .uploadedKds dans un sumMetric.uploadedKbs.

Je suppose que j'ai besoin d'une sorte de groupingBy

Stream.of(
    new MetricGroup("app1", 1,100),
    new MetricGroup("app1", 1,300),
    new MetricGroup("app2", 1,200)
)
.collect(Collector.groupingBy(MetricGroup::getApplication, accumulator??, combiner??)

Le résultat serait un flux avec:

public class MetricGroup {

    private String application;
    private int uploadedDocs;
    private long uploadedKbs;

    // getters and setters

}

Des idées?


2 commentaires

Quel est le problème avec les réponses que vous avez obtenues à votre question similaire posée il y a 30 minutes ?


J'ai besoin de regrouper par application, sur l'autre poste seulement, je dois résumer tous les objets. Maintenant, je dois résumer par application.


4 Réponses :


4
votes

Vous pouvez regrouper par application puis mapper les résultats sur MetricGroup:

source.stream()
      .collect(groupingBy(MetricGroup::getApplication))
      .entrySet().stream()
      .map(s -> new MetricGroup(s.getKey(), 
                 s.getValue().stream().mapToInt(MetricGroup::getUploadedDocs).sum(),
                 s.getValue().stream().mapToLong(MetricGroup::getUploadedKbs).sum()))
      .collect(Collectors.toList());     


0 commentaires

1
votes

vous pouvez essayer quelque chose comme ceci

groupedByAppKbs.get("app1").longValue();

Que pour accéder aux vaues:

private static final List<MetricGroup> mgArr = Arrays.asList(new MetricGroup("app1", 1,100),new MetricGroup("app1", 1,300),new MetricGroup("app2", 1,200));

Map<String, Long> groupedByAppKbs = mgArr.stream()
                .collect(groupingBy(MetricGroup::getApplication, summingLong(MetricGroup::getUploadedKbs)));


0 commentaires

2
votes

Si vous pouviez ajouter le constructeur de copie et la méthode merge suivants à la classe MetricGroup :

Map<String, MetricGroup> result = Stream.of(
        new MetricGroup("app1", 1,100), 
        new MetricGroup("app1", 1,300), 
        new MetricGroup("app2", 1,200))
.collect(Collectors.toMap(
        MetricGroup::getApplication, 
        MetricGroup::new,      // use copy constructor
        MetricGroup::merge));  // use MetricGroup.merge method

Ensuite, vous pouvez utiliser Collectors.toMap pour regrouper les métriques par application:

public MetricGroup(MetricGroup another) {
    this.application = another.application;
    this.uploadedDocs = another.uploadedDocs;
    this.uploadedKbs = another.uploadedKbs;
}

public MetricGroup merge(MetricGroup another) {
    this.uploadedDocs += another.uploadedDocs;
    this.uploadedKbs += another.uploadedKbs;
    return this;
}

Notez que nous devons utiliser le constructeur de copie pour ne pas muter le MetricGroup code> éléments du flux.


0 commentaires

1
votes

Utilisez Collectors.reducing lors du regroupement par MetricGroup.application:

Map<String, MetricGroup> collect = 
      source.stream()
            .collect(
                   groupingBy(MetricGroup::getApplication,
                              reducing(new MetricGroup(null, 0, 0),
                                       (m1, m2) -> new MetricGroup(
                                               m2.application,
                                               m1.getUploadedDocs() + m2.getUploadedDocs(),
                                               m1.getUploadedKbs() + m2.getUploadedKbs()))));


0 commentaires