This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package ru.soune.nocopy.util;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@UtilityClass
|
||||
public class PercentileCalculator {
|
||||
|
||||
/**
|
||||
* Рассчитать несколько перцентилей за один проход
|
||||
*
|
||||
* @param values список значений
|
||||
* @param percentiles массив перцентилей
|
||||
* @return PercentilesResult с соответствующими значениями
|
||||
*/
|
||||
public PercentilesResult calculatePercentiles(List<Long> values, int... percentiles) {
|
||||
if (values == null || values.isEmpty()) {
|
||||
return new PercentilesResult(0L, 0L, 0L);
|
||||
}
|
||||
|
||||
List<Long> sorted = values.stream()
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Long p5 = percentiles.length > 0 ? calculatePercentileFromSorted(sorted, percentiles[0]) : 0L;
|
||||
Long p50 = percentiles.length > 1 ? calculatePercentileFromSorted(sorted, percentiles[1]) : 0L;
|
||||
Long p95 = percentiles.length > 2 ? calculatePercentileFromSorted(sorted, percentiles[2]) : 0L;
|
||||
|
||||
return new PercentilesResult(p5, p50, p95);
|
||||
}
|
||||
|
||||
public PercentilesResult calculateP5P50P95(List<Long> values) {
|
||||
return calculatePercentiles(values, 5, 50, 95);
|
||||
}
|
||||
|
||||
private Long calculatePercentileFromSorted(List<Long> sorted, double percentile) {
|
||||
if (sorted.isEmpty()) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
if (percentile <= 0) {
|
||||
return sorted.get(0);
|
||||
}
|
||||
if (percentile >= 100) {
|
||||
return sorted.get(sorted.size() - 1);
|
||||
}
|
||||
|
||||
double index = (percentile / 100.0) * (sorted.size() - 1);
|
||||
int lowerIndex = (int) Math.floor(index);
|
||||
int upperIndex = (int) Math.ceil(index);
|
||||
|
||||
if (lowerIndex == upperIndex) {
|
||||
return sorted.get(lowerIndex);
|
||||
}
|
||||
|
||||
double weight = index - lowerIndex;
|
||||
long lowerValue = sorted.get(lowerIndex);
|
||||
long upperValue = sorted.get(upperIndex);
|
||||
|
||||
return lowerValue + Math.round(weight * (upperValue - lowerValue));
|
||||
}
|
||||
|
||||
public static class PercentilesResult {
|
||||
private final Long p5;
|
||||
private final Long p50;
|
||||
private final Long p95;
|
||||
|
||||
public PercentilesResult(Long p5, Long p50, Long p95) {
|
||||
this.p5 = p5;
|
||||
this.p50 = p50;
|
||||
this.p95 = p95;
|
||||
}
|
||||
|
||||
public Long getP5() { return p5; }
|
||||
public Long getP50() { return p50; }
|
||||
public Long getP95() { return p95; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user