package net.iponweb.disthene.reader.utils; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * @author Andrei Ivanov */ public class CollectionUtils { public static Double average(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); if (filteredValues.size() == 0) return null; double sum = 0; for(Double value : filteredValues) { sum += value; } return sum / filteredValues.size(); } public static Double median(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); if (filteredValues.size() == 0) return 0.; if (filteredValues.size() == 1) return filteredValues.get(0); Collections.sort(filteredValues); if (filteredValues.size() % 2 == 0) { return (filteredValues.get(filteredValues.size() / 2) + filteredValues.get(filteredValues.size() / 2 - 1)) / 2.; } else { return filteredValues.get(filteredValues.size() / 2); } } public static Double sum(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); if (filteredValues.size() == 0) return null; double sum = 0; for(Double value : filteredValues) { sum += value; } return sum; } public static Double product(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); double sum = 1; for(Double value : filteredValues) { sum *= value; } return sum; } public static Double stdev(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); if (filteredValues.size() < 2) return null; Double average = average(filteredValues); if (average == null) return null; double variance = 0; for(Double value : filteredValues) { variance += (value - average) * (value - average); } return Math.sqrt(variance / filteredValues.size()) ; } public static Double percentile(Collection<Double> values, double percentile, boolean interpolate) { List<Double> filteredValues = filterNulls(values); Collections.sort(filteredValues); if (filteredValues.size() == 0) return null; double fractionalRank = (percentile / 100.0) * (filteredValues.size() + 1); int rank = (int) fractionalRank; double rankFraction = fractionalRank - rank; double result; if (!interpolate) { rank += (int) Math.ceil(rankFraction); } if (rank == 0) { result = filteredValues.get(0); } else if (rank == filteredValues.size() + 1) { result = filteredValues.get(filteredValues.size() - 1); } else { result = filteredValues.get(rank - 1); } if (interpolate && rank != filteredValues.size()) { result = result + rankFraction * (filteredValues.get(rank) - result); } return result; } public static Double last(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); return filteredValues.size() > 0 ? filteredValues.get(filteredValues.size() - 1) : null; } public static Double first(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); return filteredValues.size() > 0 ? filteredValues.get(0) : null; } public static Double max(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); if (filteredValues.size() == 0) return null; return Collections.max(filteredValues); } public static Double min(Collection<Double> values) { List<Double> filteredValues = filterNulls(values); if (filteredValues.size() == 0) return null; return Collections.min(filteredValues); } public static void constant(Double[] values, Double constant) { for (int i = 0; i < values.length; i++) { values[i] = constant; } } private static List<Double> filterNulls(Collection<Double> values) { List<Double> result = new ArrayList<>(); for(Double value : values) { if (value != null) result.add(value); } return result; } // faster but unsafe methods assuming all values are not nulls and list is not empty public static Double unsafeSum(Collection<Double> values) { // shortcut if there is only one value if (values.size() == 1) return values.iterator().next(); double sum = 0; for(Double value : values) { sum += value; } return sum; } public static Double unsafeAverage(Collection<Double> values) { // shortcut if there is only one value if (values.size() == 1) return values.iterator().next(); double sum = 0; for(Double value : values) { sum += value; } return sum / values.size(); } }