spacemanjosh
spacemanjosh

Reputation: 691

Find average using Java DoubleStream filtering out NaNs

I'm sure there is a simple way to do this, but I'm not finding it.

Essentially, what I want to do is utilize a Java DoubleStream to calculate various things, like for example the average of an array of values. BUT, the array may contain NaN values, which of course will cause the result to also be a NaN. So I want to somehow, in a one-liner, filter out the NaNs and compute the average.

For example, this code will produce a result of NaN, which I don't want.

import java.util.stream.DoubleStream;

public class StreamTests {
    public static void main(String[] args) {
        double[] x = {3.14159, 42, 2.71828, Double.NaN};
        double mean = DoubleStream.of(x).average().getAsDouble();
        System.out.println(mean);
    }
}

What I'd like to do is something more like this:

import java.util.stream.DoubleStream;

public class StreamTests {
    public static void main(String[] args) {
        double[] x = {3.14159, 42, 2.71828, Double.NaN};
        double mean = DoubleStream.of(x).ifNotNaN().average().getAsDouble();
        System.out.println(mean);
    }
}

For example, I can do this kind of thing in Python:

import math
x = [3.14159, 42, 2.71828, float('NaN')]
mean = sum([i for i in x if not math.isnan(i)]) / len(x)
print(mean)

I'm aware of why the NaN is produced in the first code block, just standard floating-point behavior. And I'm also aware that I could just loop over the values and check each one, etc., but that's exactly what I'm trying to avoid. I'd like the code to be a little more compact and elegant.

Upvotes: 1

Views: 1094

Answers (1)

rgettman
rgettman

Reputation: 178293

Use the filter method, passing in a DoublePredicate that uses Double.isNaN to filter them out.

double mean = DoubleStream.of(x)
    .filter(d -> !Double.isNaN(d)) 
    .average().getAsDouble();

Upvotes: 6

Related Questions