I apologize for that title, lol.
I have a Java method that I'm writing where I want to be able to pass in an array of Objects and two interfaces that will be used for lambda expressions that specify a particular value to use for calculation.
It's part of a larger class that I want to use for all kinds of Statistics calculations, but I started with calculating correlation because it's most relevant to the specific problem I want to solve.
import java.lang.IllegalArgumentException;
import java.util.Arrays;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.List;
public class Statistics
{
//1. This method is really unreadable
public static <O> double getCorrelation(O[] a, Fetchable<O, Double> dataPointA, Fetchable<O, Double> dataPointB)
{
Double[] temp = Arrays.stream(a).map(x -> dataPointA.fetch(x)).collect(Collectors.toList()).toArray(new Double[0]);
Double[] temp2 = Arrays.stream(a).map(x -> dataPointB.fetch(x)).collect(Collectors.toList()).toArray(new Double[0]);
return getCorrelation(temp, temp2);
}
public static double getCorrelation(double[] a, double[] b)
{
if (a.length != b.length)
{
//2. Is this the best Exception for this case?
throw new IllegalArgumentException();
}
double sumA = 0.0;
double sumB = 0.0;
double sumSquareA = 0.0;
double sumSquareB = 0.0;
double sumAB = 0.0;
for(int i = 0; i < a.length; i++)
{
sumA += a[i];
sumB += b[i];
sumSquareA += a[i] * a[i];
sumSquareB += b[i] * b[i];
sumAB += a[i] * b[i];
}
int n = a.length;
return (n * sumAB - sumA * sumB) / (Math.sqrt(n * sumSquareA - sumA * sumA) * Math.sqrt(n * sumSquareB - sumB * sumB));
}
private static double getCorrelation(Double[] a, Double[] b)
{
if (a.length != b.length)
{
//2. Is this the best Exception for this case?
throw new IllegalArgumentException();
}
//3. Is there a better way to do this conversion from Double[] to double[]?
double doubleArrA[] = new double[a.length];
double doubleArrB[] = new double[a.length];
for (int i = 0; i < a.length; i++)
{
doubleArrA[i] = (double)a[i];
doubleArrB[i] = (double)b[i];
}
return getCorrelation(doubleArrA, doubleArrB);
}
interface Fetchable<T1, T2>
{
public T2 fetch(T1 a);
}
//main function for testing
public static void main(String[] args)
{
//this class is defined in another file; it's a simple class with four public doubles I made just to test
TestDataPoint a[] = new TestDataPoint[5];
a[0] = new TestDataPoint();
a[0].w = 3;
a[0].x = 0;
a[0].y = 4;
a[0].z = 9;
a[1] = new TestDataPoint();
a[1].w = 1;
a[1].x = 8;
a[1].y = 3;
a[1].z = 2;
a[2] = new TestDataPoint();
a[2].w = 7;
a[2].x = 4;
a[2].y = 4;
a[2].z = 0;
a[3] = new TestDataPoint();
a[3].w = 3;
a[3].x = 1;
a[3].y = 0;
a[3].z = 1;
a[4] = new TestDataPoint();
a[4].w = 6;
a[4].x = 3;
a[4].y = 9;
a[4].z = 8;
a[1] = new TestDataPoint();
System.out.println(getCorrelation(a, p -> p.w, q -> q.z));
System.out.println(getCorrelation(a, p -> p.x, q -> q.z));
System.out.println(getCorrelation(a, p -> p.y, q -> q.z));
System.out.println(getCorrelation(a, p -> p.z, q -> q.z));
}
}
It works pretty well; I've tried it and it seems to do exactly what I want. There are a few things I want to look at, though:
- That crazy method is absurdly unreadable.
- Is IllegalArgumentException the best Exception for the case where the method cannot execute properly because arrays of differing lengths are provided?
- Is there any easily readable way to convert Double[] to double[] without the loop I used in getCorrelation(Double[] a, Double[] b)?
Thanks in advance.