4
\$\begingroup\$

I have this method which calculates the average, median and percentile information given a long array of numbers. Is there any better and efficient way to do the same?

  public static double median(long[] numbers) {
    Arrays.sort(numbers, 0, numbers.length);
    int middle = numbers.length / 2;
    if (numbers.length % 2 == 1) {
      return numbers[middle];
    } else {
      return (numbers[middle - 1] + numbers[middle]) / 2.0;
    }
  }

  public static double average(long[] numbers) {
    int sum = 0;
    for (long l : numbers)
      sum += l;
    double average = 1.0d * sum / numbers.length;
    return average;
  }

  public static long[] percentiles(long[] numbers, double... percentiles) {
    Arrays.sort(numbers, 0, numbers.length);
    long[] values = new long[percentiles.length];
    for (int i = 0; i < percentiles.length; i++) {
      int index = (int) (percentiles[i] * numbers.length);
      values[i] = numbers[index];
    }
    return values;
  }
\$\endgroup\$
2
\$\begingroup\$

Validate your inputs

The median and average methods will throw an exception if the input array is empty. Think of the preconditions and if there are safe assumptions (input will never be empty) then document it, possibly with an assert statement, for example:

assert numbers.length > 0;

Note that the primary purpose of asset statements is documentation. Although a failed assert will crash the program, but only during development, as assert statements are removed from release builds, and so don't get executed in production. If you want to validate input, use exceptions instead.

Watch out for corner cases

This statement may overflow if the two numbers are too big:

return (numbers[middle - 1] + numbers[middle]) / 2.0;

To avoid overflow, you could divide each by 2 and then sum.

Simplify

If you omit the second and third parameters of Arrays.sort, by default it will use 0 and the length of the array. So you can omit these parameters in all your examples.

There is already a library method to calculate average:

return LongStream.of(numbers).average();
\$\endgroup\$
  • \$\begingroup\$ I am still on Java 7 and looks like LongStream is part of Java 8. Is there any alternative in Java 7? Also how can I fix overflow case as you mentioned out? Yeah in my case input will never be empty so still I should use Assert statement (I always thought we use assert in unit test)? \$\endgroup\$ – user5447339 Dec 15 '16 at 20:31
  • \$\begingroup\$ I added more details to my post to answer some of your follow up questions, except concerning the Java 8 features, which don't have an equivalent in Java 7 \$\endgroup\$ – janos Dec 15 '16 at 23:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.