How to get the min/max element of nested collections without redundant code using streams?

Viewed 198

For example:

Given a Set<Set<Integer>>, I have tried to use

int min = nestedSets.stream().map(s->s.stream().min(Comparator.naturalOrder()).get()).min(Comparator.naturalOrder()).get();

My initial idea was to use flatMap, however it doesn't returns the desired result.

3 Answers

You can collect the elements into an IntSummaryStatistics, which is:

A state object for collecting statistics such as count, min, max, sum, and average.

For example:

Set<Set<Integer>> set = ...;

IntSummaryStatistics stats =
    set.stream()                      // Stream<Set<Integer>>
        .flatMap(Set::stream)         // Stream<Integer>
        .mapToInt(Integer::intValue)  // IntStream
        .summaryStatistics();         // IntSummaryStatistics

int min = stats.getMin();
int max = stats.getMax();

If no values were recorded then #getMin() returns Integer.MAX_VALUE and #getMax() returns Integer.MIN_VALUE.

    Set<Set<Integer>> nestedSets = ...

    IntSummaryStatistics stats = nestedSets.stream()
                                           .flatMap(Set::stream)
                                           .mapToInt(Integer::intValue)
                                           .summaryStatistics();

    stats.getMax();
    stats.getMin();

The returned type should be OptionalInt since you don't know it the minimum value is found. You can do:

OptionalInt min = nestedSets.stream()
    .flatMap(Set::stream)
    .mapToInt(Integer::intValue)
    .min();

Alternatively, you can use Comparator with the very same mapping function (Integer::intValue) inside Stream::min which results in boxed Optional<Integer> instead:

Optional<Integer> min = nestedSets.stream()
    .flatMap(Set::stream)
    .min(Comparator.comparingInt(Integer::intValue));

It depends if you need all these values or just either min or max.

  • Pros: I find these solutions easy to read, with no redundant code and the best way to compute min/max/avg or more.

  • Cons: You can compute only one value (either min or max) at the same time. Use IntSummaryStatistics for summary computations otherwise as already answered here.

Related