6

I have a stream of Events

public class Event {
    Location location;
    double turnout;
    //... other fields & getters
}

And a statistics class EventStatistics

public class EventStatistics {
    // Stats properties e.g. turnout standard deviation/median

    public EventStatistics(List<Event> events) {
        // Generate stats
    }
}

I need to group all the events by location & create a map of location and event statistics Map<Location, EventStatistics>

The group by is just:

Map<Location, List<Event>> byLocation = events.stream().collect(groupingBy(Event::getLocation));

I know there is an overloaded groupingBy(function, collector) collector. Can I use somehow this to generate my Map<Location, EventStatistics> in a single stream?

0

3 Answers 3

14

All you need is collectingAndThen:

Map<Location, EventStatistics> result = 
    events.stream()
          .collect(Collectors.groupingBy(Event::getLocation,
                                         Collectors.collectingAndThen(
                                             Collectors.toList(), 
                                             EventStatistics::new)));
Sign up to request clarification or add additional context in comments.

Comments

2

You can construct your own Collector using Collector.of(...), like this:

Map<Location, EventStatistics> collect = events.stream().collect(groupingBy(Event::getLocation,
        Collector.of(ArrayList::new,
                     List::add,
                     (left, right) -> { left.addAll(right); return left; },
                     EventStatistics::new)
));

1 Comment

This code doesn't compile for me. ArrayList::new doesn't infer the Event type. I need to specify ArrayList<Event>::new.
1

If your EventStatistics were to be able to accept single Events instead of a full list, and a method to merge two statistics, as in

EventStatistics {
    public EventStatistics() {}
    public void addEvent(Event e);
    public EventStatistics merge(EventStatistics toMerge);
}

then you can do

groupingBy(Event::getLocation, Collector.of(EventStatistics::new, EventStatistics::accept, EventStatistics::merge));

Here, the argument-less constructor is the Supplier, the accept is the accumulator, and the merge is the combiner.

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.