1

I've a stream of MetricGroup, where:

public class MetricGroup {

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

    // getters and setters

}

I need to sumarize all application metrics. I mean, for each application (MetricGroup.application) I need to add all metric.uploadedDocs into a sumMetric.uploadedDocs and metric.uploadedKds into a sumMetric.uploadedKbs.

I figure out I need some kind of 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??)

The result would be a stream with:

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

Any ideas?

2
  • 2
    What's wrong with the answers you got on your similar question asked 30 mins ago? Commented Jan 8, 2019 at 11:02
  • 1
    I need to group by application, On the other post only I need to summarize all objects. Now I need to summarize by application. Commented Jan 8, 2019 at 11:03

4 Answers 4

4

You can group by application and then map the results to 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());     
Sign up to request clarification or add additional context in comments.

Comments

2

If you could add the following copy constructor and merge method to the MetricGroup class:

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

Then, you could use Collectors.toMap to group metrics by application:

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

Note that we need to use the copy constructor to not mutate the original MetricGroup elements of the stream.

Comments

1

you can try something like this

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

Than to access the vaues:

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

Comments

1

Use Collectors.reducing while grouping by 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()))));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.