mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-23 09:37:54 +01:00
[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:
parent
ded4d01e53
commit
91d8731ab5
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user