From 91d8731ab5b099a193cabdb58c01630683a835d1 Mon Sep 17 00:00:00 2001 From: Fuzzlemann Date: Mon, 29 Oct 2018 13:42:50 +0100 Subject: [PATCH] [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 --- .../data/store/mutators/SessionsMutator.java | 2 +- .../player/PingInsertProcessor.java | 2 +- .../plan/utilities/analysis/Median.java | 33 +++++++++---------- .../formatting/DecimalFormatter.java | 8 ++--- .../player/PingInsertProcessorTest.java | 2 +- .../plan/utilities/analysis/MedianTest.java | 17 +++++----- 6 files changed, 31 insertions(+), 33 deletions(-) diff --git a/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/SessionsMutator.java b/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/SessionsMutator.java index 12096cf50..5ad7ff38d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/SessionsMutator.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/SessionsMutator.java @@ -160,7 +160,7 @@ public class SessionsMutator { public long toMedianSessionLength() { List sessionLengths = sessions.stream().map(Session::getLength).collect(Collectors.toList()); - return (long) Median.forLong(sessionLengths).calculate(); + return (long) Median.forList(sessionLengths).calculate(); } public int toAverageUniqueJoinsPerDay() { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/PingInsertProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/PingInsertProcessor.java index 9f0bdc4b9..8a46eb9bf 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/PingInsertProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/PingInsertProcessor.java @@ -84,6 +84,6 @@ public class PingInsertProcessor implements CriticalRunnable { } int getMeanValue(List> 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(); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Median.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Median.java index f4afa5b8c..b347c26a5 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Median.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Median.java @@ -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 a {@code Number} object which implements {@code Comparable} (In general every standard Java number) * @author Rsl1122 */ -public class Median { +public class Median> { - private final List values; + private final List values; private int size; - private Median(Collection values, int b) { - this(values.stream().map(i -> (long) i).collect(Collectors.toList())); - } - - private Median(List values) { + private Median(List values) { this.values = values; Collections.sort(values); size = values.size(); } - public static Median forInt(Collection integers) { - return new Median(integers, 0); - } - - public static Median forLong(List 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 > Median forList(List 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(); } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/formatting/DecimalFormatter.java b/Plan/src/main/java/com/djrapitops/plan/utilities/formatting/DecimalFormatter.java index e27c8cd18..cdc59d3da 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/formatting/DecimalFormatter.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/formatting/DecimalFormatter.java @@ -28,14 +28,14 @@ import java.text.DecimalFormat; */ public class DecimalFormatter implements Formatter { - 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); } -} \ No newline at end of file +} diff --git a/Plan/src/test/java/com/djrapitops/plan/system/processing/processors/player/PingInsertProcessorTest.java b/Plan/src/test/java/com/djrapitops/plan/system/processing/processors/player/PingInsertProcessorTest.java index 050bdc182..a97ddef55 100644 --- a/Plan/src/test/java/com/djrapitops/plan/system/processing/processors/player/PingInsertProcessorTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/system/processing/processors/player/PingInsertProcessorTest.java @@ -37,7 +37,7 @@ public class PingInsertProcessorTest { public void medianCalculation() { List 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); diff --git a/Plan/src/test/java/com/djrapitops/plan/utilities/analysis/MedianTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/analysis/MedianTest.java index 50a0a3656..d99429fb9 100644 --- a/Plan/src/test/java/com/djrapitops/plan/utilities/analysis/MedianTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/analysis/MedianTest.java @@ -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 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 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()).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 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 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 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 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); }