[Merge] Median and DecimalFormatter improvements (#765) by Fuzzlemann

* Generified Median.java
* Improves performance when comparing Integers because of Collection -> Stream -> List conversion removal. Instead of Median.forInt or Median.forLong Median.forList can be used.
* Now every type of number can be compared
* Storing DecimalFormat rather than creating a new DecimalFormat object each time it's applied
* Added JavaDocs for Median.java
This commit is contained in:
Fuzzlemann 2018-10-29 13:42:50 +01:00 committed by Risto Lahtela
parent ded4d01e53
commit 91d8731ab5
6 changed files with 31 additions and 33 deletions

View File

@ -160,7 +160,7 @@ public class SessionsMutator {
public long toMedianSessionLength() {
List<Long> sessionLengths = sessions.stream().map(Session::getLength).collect(Collectors.toList());
return (long) Median.forLong(sessionLengths).calculate();
return (long) Median.forList(sessionLengths).calculate();
}
public int toAverageUniqueJoinsPerDay() {

View File

@ -84,6 +84,6 @@ public class PingInsertProcessor implements CriticalRunnable {
}
int getMeanValue(List<DateObj<Integer>> history) {
return (int) Median.forInt(history.stream().map(DateObj::getValue).collect(Collectors.toList())).calculate();
return (int) Median.forList(history.stream().map(DateObj::getValue).collect(Collectors.toList())).calculate();
}
}

View File

@ -16,37 +16,34 @@
*/
package com.djrapitops.plan.utilities.analysis;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* Math utility for calculating the median from Integer values.
*
* @param <T> a {@code Number} object which implements {@code Comparable} (In general every standard Java number)
* @author Rsl1122
*/
public class Median {
public class Median<T extends Number & Comparable<? super T>> {
private final List<Long> values;
private final List<T> values;
private int size;
private Median(Collection<Integer> values, int b) {
this(values.stream().map(i -> (long) i).collect(Collectors.toList()));
}
private Median(List<Long> values) {
private Median(List<T> values) {
this.values = values;
Collections.sort(values);
size = values.size();
}
public static Median forInt(Collection<Integer> integers) {
return new Median(integers, 0);
}
public static Median forLong(List<Long> longs) {
return new Median(longs);
/**
* Creates a Median instance
*
* @param list the input list
* @return an instance of {@code Median} for the List given
*/
public static <T extends Number & Comparable<? super T>> Median<T> forList(List<T> list) {
return new Median<>(list);
}
public double calculate() {
@ -62,13 +59,13 @@ public class Median {
private double calculateEven() {
int half = size / 2;
double x1 = values.get(half);
double x2 = values.get(half - 1);
double x1 = values.get(half).doubleValue();
double x2 = values.get(half - 1).doubleValue();
return (x1 + x2) / 2;
}
private double calculateOdd() {
int half = size / 2;
return (double) values.get(half);
return values.get(half).doubleValue();
}
}

View File

@ -28,14 +28,14 @@ import java.text.DecimalFormat;
*/
public class DecimalFormatter implements Formatter<Double> {
private final PlanConfig config;
private volatile DecimalFormat decimalFormat;
public DecimalFormatter(PlanConfig config) {
this.config = config;
decimalFormat = new DecimalFormat(config.getString(Settings.FORMAT_DECIMALS));
}
@Override
public String apply(Double value) {
return new DecimalFormat(config.getString(Settings.FORMAT_DECIMALS)).format(value);
return decimalFormat.format(value);
}
}
}

View File

@ -37,7 +37,7 @@ public class PingInsertProcessorTest {
public void medianCalculation() {
List<Integer> collect = testPing.stream().map(DateObj::getValue).sorted().collect(Collectors.toList());
int expected = (int) Median.forInt(collect).calculate();
int expected = (int) Median.forList(collect).calculate();
int result = new PingInsertProcessor(TestConstants.PLAYER_ONE_UUID, TestConstants.SERVER_UUID, new ArrayList<>(), null)
.getMeanValue(testPing);

View File

@ -2,6 +2,7 @@ package com.djrapitops.plan.utilities.analysis;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -20,7 +21,7 @@ public class MedianTest {
List<Integer> testValues = Arrays.asList(1, 3, 3, 6, 7, 8, 9);
Collections.shuffle(testValues);
double expected = 6;
double result = Median.forInt(testValues).calculate();
double result = Median.forList(testValues).calculate();
assertEquals(expected, result, 0.01);
}
@ -30,7 +31,7 @@ public class MedianTest {
List<Integer> testValues = Arrays.asList(1, 2, 3, 4, 5, 6, 8, 9);
Collections.shuffle(testValues);
double expected = 4.5;
double result = Median.forInt(testValues).calculate();
double result = Median.forList(testValues).calculate();
assertEquals(expected, result, 0.01);
}
@ -38,7 +39,7 @@ public class MedianTest {
@Test
public void empty() {
double expected = -1;
double result = Median.forInt(Collections.emptyList()).calculate();
double result = Median.forList(new ArrayList<Integer>()).calculate();
assertEquals(expected, result, 0.01);
}
@ -46,7 +47,7 @@ public class MedianTest {
@Test
public void singleValue() {
double expected = 50;
double result = Median.forInt(Collections.singletonList((int) expected)).calculate();
double result = Median.forList(Collections.singletonList((int) expected)).calculate();
assertEquals(expected, result, 0.01);
}
@ -55,7 +56,7 @@ public class MedianTest {
public void twoValues() {
List<Integer> testValues = Arrays.asList(1, 2);
double expected = 1.5;
double result = Median.forInt(testValues).calculate();
double result = Median.forList(testValues).calculate();
assertEquals(expected, result, 0.01);
}
@ -64,7 +65,7 @@ public class MedianTest {
public void overflowOdd() {
List<Integer> testValues = Arrays.asList(Integer.MIN_VALUE, 2, Integer.MAX_VALUE);
double expected = 2;
double result = Median.forInt(testValues).calculate();
double result = Median.forList(testValues).calculate();
assertEquals(expected, result, 0.01);
}
@ -73,7 +74,7 @@ public class MedianTest {
public void overflowEven() {
List<Integer> testValues = Arrays.asList(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
double expected = -0.5;
double result = Median.forInt(testValues).calculate();
double result = Median.forList(testValues).calculate();
assertEquals(expected, result, 0.01);
}
@ -82,7 +83,7 @@ public class MedianTest {
public void overflowEven2() {
List<Integer> testValues = Arrays.asList(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
double expected = Integer.MAX_VALUE;
double result = Median.forInt(testValues).calculate();
double result = Median.forList(testValues).calculate();
assertEquals(expected, result, 0.01);
}