16

I'm looking for most elegant way to create DoubleStream (for using sum, average, etc.) from a List<Double>. At the moment I have such code:

List<Double> doubles = getListOfDoubles();
double sum = doubles.stream()
                    .mapToDouble(d -> d)
                    .sum();

Maybe anyone could suggest a shorter way?

Tunaki
  • 132,869
  • 46
  • 340
  • 423
Anatrollik
  • 313
  • 1
  • 3
  • 11
  • 1
    I mean, we have overloaded Arrays.toStream(...) that could return different Streams, so why there is nothing similar for Collections? – Anatrollik Sep 14 '15 at 13:00
  • Where is there something like this in `Arrays`? – RealSkeptic Sep 14 '15 at 13:14
  • @RealSkeptic [Arrays javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html) `static DoubleStream stream(double[] array) Returns a sequential DoubleStream with the specified array as its source.` Similar for IntStream, LongStream P.S. Sorry for formatting – Anatrollik Sep 14 '15 at 13:17
  • But that takes an array of `double` (the primitive), not an array of `Double`. And that's the difference from `Collections`. – RealSkeptic Sep 14 '15 at 13:19
  • A side note: You might have found the [DoubleStream#boxed](https://docs.oracle.com/javase/8/docs/api/java/util/stream/DoubleStream.html#boxed--) method, which basically converts a `DoubleStream` to a `Stream`. Just in case you wonder why there is no similar `unboxed` method: For the reverse direction, you have to **care for the case that one of the `Double` objects in the input is `null`**. – Marco13 Sep 14 '15 at 13:54
  • 2
    @Marco13: `mapToDouble` *is* the unbox method. That’s the only way to provide such functionality on a *generic* `Stream`. You have to specify which of the three alternatives (`IntStream`, `LongStream` or `DoubleStream`) to produce and you have to specify a function that can convert the element type, not known to the stream at runtime, to the target type. That’s exactly what `mapToDouble(ToDoubleFunction)` offers. – Holger Sep 14 '15 at 14:45
  • It is not a specific "unboxing" method, but a generic method of mapping *anything* to `double` (and its counterpart is `DoubleStream#mapToObj`). But I guess that's clear. – Marco13 Sep 14 '15 at 14:58
  • @Marco13: there is no reason why a method can’t fulfill two purposes. It’s the canonical unboxing method *and* a way of mapping anything to double. `DoubleStream.boxed()` is just a convenience method for `mapToObj(Double::valueOf)` anyway… – Holger Sep 15 '15 at 10:09

2 Answers2

21

The best way to obtain statistics from a Stream is to use the ...SummaryStatistics classes. For a Stream<Double>, this is DoubleSummaryStatistics:

List<Double> doubles = getListOfDoubles();
DoubleSummaryStatistics stats = doubles.stream().collect(Collectors.summarizingDouble(Double::doubleValue));
System.out.println(stats.getAverage());
System.out.println(stats.getSum());

It is obtained by collecting the stream with the summarizingDouble collector. This collector takes a ToDoubleFunction as argument: it is a function which should return the double to analyze.

Such statistics can be obtained for Integer, Long and Double values.

Note that the general case of converting a Collection<Double> to a DoubleStream can be done with the code you already have:

List<Double> doubles = getListOfDoubles();
DoubleStream stream = doubles.stream().mapToDouble(Double::doubleValue);
Tunaki
  • 132,869
  • 46
  • 340
  • 423
1

You can do (even it's not significantly shorter, but...):

double sum = doubles.stream().collect(Collectors.summingDouble(x -> x));

or

double sum = DoubleStream.of(doubles.stream().mapToDouble(x->x).toArray()).sum();

but the latter is more or less the same as your approach.

Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
  • 3
    Not really. Storing the entire stream into an intermediate array is a waste of resources without any advantage over all other solutions shown here. – Holger Sep 14 '15 at 13:38