потоки Java: группировка и добавление полей - PullRequest
0 голосов
/ 08 января 2019

У меня есть поток MetricGroup, где:

public class MetricGroup {

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

    // getters and setters

}

Мне нужно обобщить все метрики приложения. Я имею в виду, что для каждого приложения (MetricGroup.application) мне нужно добавить все metric.uploadedDocs в sumMetric.uploadedDocs и metric.uploadedKds в sumMetric.uploadedKbs.

Я понял, мне нужен какой-то 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??)

Результатом будет поток с:

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

Есть идеи?

Ответы [ 4 ]

0 голосов
/ 08 января 2019

Используйте Collectors.reducing при группировании по 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 голосов
/ 08 января 2019

вы можете попробовать что-то вроде этого

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

Чем получить доступ к vaues:

groupedByAppKbs.get("app1").longValue();
0 голосов
/ 08 января 2019

Если бы вы могли добавить следующий конструктор копирования и метод merge к классу MetricGroup:

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

Затем вы можете использовать Collectors.toMap для группировки метрик по приложению:

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

Обратите внимание, что нам нужно использовать конструктор копирования, чтобы не изменять исходные MetricGroup элементы потока.

0 голосов
/ 08 января 2019

Вы можете сгруппировать по application и затем сопоставить результаты с 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());     
...