001/* 002 * Copyright (C) Photon Vision. 003 * 004 * This program is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 * 014 * You should have received a copy of the GNU General Public License 015 * along with this program. If not, see <https://www.gnu.org/licenses/>. 016 */ 017 018package org.photonvision.common.util.numbers; 019 020import java.math.BigDecimal; 021import java.util.ArrayList; 022import java.util.Comparator; 023import java.util.List; 024import java.util.StringJoiner; 025 026@SuppressWarnings("unused") 027public class NumberListUtils { 028 /** 029 * @param collection an ArrayList of Comparable objects 030 * @return the median of collection 031 */ 032 public static <T extends Number> double median(List<T> collection, Comparator<T> comp) { 033 double result; 034 int n = collection.size() / 2; 035 036 if (collection.size() % 2 == 0) // even number of items; find the middle two and average them 037 result = 038 (nthSmallest(collection, n - 1, comp).doubleValue() 039 + nthSmallest(collection, n, comp).doubleValue()) 040 / 2.0; 041 else // odd number of items; return the one in the middle 042 result = nthSmallest(collection, n, comp).doubleValue(); 043 044 return result; 045 } 046 047 public static <T extends Number> String toString(List<T> collection) { 048 return toString(collection, ""); 049 } 050 051 public static <T extends Number> String toString(List<T> collection, String suffix) { 052 StringJoiner joiner = new StringJoiner(", "); 053 for (T x : collection) { 054 String s = x.doubleValue() + suffix; 055 joiner.add(s); 056 } 057 return joiner.toString(); 058 } 059 060 /** 061 * @param collection an ArrayList of Numbers 062 * @return the mean of collection 063 */ 064 public static double mean(final List<? extends Number> collection) { 065 BigDecimal sum = BigDecimal.ZERO; 066 for (final Number number : collection) { 067 sum = sum.add(BigDecimal.valueOf(number.doubleValue())); 068 } 069 return (sum.doubleValue() / collection.size()); 070 } 071 072 /** 073 * @param collection a collection of Comparable objects 074 * @param n the position of the desired object, using the ordering defined on the collection 075 * elements 076 * @return the nth smallest object 077 */ 078 public static <T> T nthSmallest(List<T> collection, int n, Comparator<T> comp) { 079 T result, pivot; 080 ArrayList<T> underPivot = new ArrayList<>(), 081 overPivot = new ArrayList<>(), 082 equalPivot = new ArrayList<>(); 083 084 // choosing a pivot is a whole topic in itself. 085 // this implementation uses the simple strategy of grabbing something from the middle of the 086 // ArrayList. 087 088 pivot = collection.get(n / 2); 089 090 // split collection into 3 lists based on comparison with the pivot 091 092 for (T obj : collection) { 093 int order = comp.compare(obj, pivot); 094 095 if (order < 0) // obj < pivot 096 underPivot.add(obj); 097 else if (order > 0) // obj > pivot 098 overPivot.add(obj); 099 else // obj = pivot 100 equalPivot.add(obj); 101 } // for each obj in collection 102 103 // recurse on the appropriate collection 104 105 if (n < underPivot.size()) result = nthSmallest(underPivot, n, comp); 106 else if (n < underPivot.size() + equalPivot.size()) // equal to pivot; just return it 107 result = pivot; 108 else // everything in underPivot and equalPivot is too small. Adjust n accordingly in the 109 // recursion. 110 result = nthSmallest(overPivot, n - underPivot.size() - equalPivot.size(), comp); 111 112 return result; 113 } 114}