3

I have a DoubleStream which has been calculated from a very time consuming function, and I want to calculate the Average and Count of its elements at the same time.

The Problem is I do not want to calculate the DoubleStream twice because of the mentioned time consuming calculation of values. I want to get the value of both Average and Count from one lambda expression.

I have tried everything with collect and map and so on but had no success.

    final long count = products.stream()
            .mapToDouble(this::timeConsumingCalculateRating)
            .filter(rating -> rating > 0.0D)
            .count();

    final double averageRating = products.stream()
            .mapToDouble(this::timeConsumingCalculateRating)
            .filter(rating -> rating > 0.0D)
            .average()
            .orElse(0.0D);

any help is highly appreciated.

Eran
  • 387,369
  • 54
  • 702
  • 768
hoomb
  • 649
  • 2
  • 12
  • 24

2 Answers2

13

Use summaryStatistics():

DoubleSummaryStatistics stats = products.stream()
            .mapToDouble(this::timeConsumingCalculateRating)
            .filter(rating -> rating > 0.0D)
            .summaryStatistics();
long count = stats.getCount();
double averageRating = stats.getAverage();
Gerardo Cauich
  • 559
  • 5
  • 20
Eran
  • 387,369
  • 54
  • 702
  • 768
5

For count and average, summaryStatistics is all you need. But if you have some other terminal operation and you also need to count the elements, you could use peek with an AtomicLong or AtomicInteger:

AtomicLong counter = new AtomicLong();
double average = products.stream()
        .mapToDouble(this::timeConsumingCalculateRating)
        .filter(rating -> rating > 0.0D)
        .peek(d -> counter.incrementAndGet())
        .average().orElse(0.0);
long count = counter.get();
tobias_k
  • 81,265
  • 12
  • 120
  • 179