I am trying to make general class to find mode. I am looking for some general feedback on how I can improve the structure and efficiency of my code.
package analysis.statistic;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class Mode {
/**
* Return objects which appears most often.
*
* @return Map<object,countAppears> most appears objects.
*/
@SuppressWarnings("unchecked")
public static <T> Map<T, Integer> mode(T... objects) {
Objects.requireNonNull(objects, "objects must not be null");
if (objects.length == 0) {
return new HashMap<>();
}
Arrays.sort(objects);
ModeCalc<T> calc = new ModeCalc<T>(objects[0]);
for (T t : objects) {
calc.checkMaxAppears(t);
}
return calc.getMode();
}
/**
* Work like {@link #mode(Object...)}.
*/
@SuppressWarnings("unchecked")
public static <T> Map<T, Integer> mode(Comparator<? super T> c, T... objects) {
Objects.requireNonNull(objects, "objects must not be null");
if (objects.length == 0) {
return new HashMap<>();
}
Arrays.sort(objects, c);
ModeCalc<T> calc = new ModeCalc<T>(objects[0]);
for (T t : objects) {
calc.checkMaxAppears(t);
}
return calc.getMode();
}
/**
* Work like {@link #mode(Object...)}.
*/
public static Map<Integer, Integer> mode(int... numbers) {
Objects.requireNonNull(numbers, "numbers must not be null");
if (numbers.length == 0) {
return new HashMap<>();
}
Arrays.sort(numbers);
ModeCalc<Integer> calc = new ModeCalc<Integer>(numbers[0]);
for (int t : numbers) {
calc.checkMaxAppears(t);
}
return calc.getMode();
}
/**
* Work like {@link #mode(Object...)}.
*/
public static Map<Long, Integer> mode(long... numbers) {
Objects.requireNonNull(numbers, "numbers must not be null");
if (numbers.length == 0) {
return new HashMap<>();
}
Arrays.sort(numbers);
ModeCalc<Long> calc = new ModeCalc<>(numbers[0]);
for (long t : numbers) {
calc.checkMaxAppears(t);
}
return calc.getMode();
}
/**
* Work like {@link #mode(Object...)}.
*/
public static Map<Double, Integer> mode(double... numbers) {
Objects.requireNonNull(numbers, "numbers must not be null");
if (numbers.length == 0) {
return new HashMap<>();
}
Arrays.sort(numbers);
ModeCalc<Double> calc = new ModeCalc<Double>(numbers[0]);
for (double t : numbers) {
calc.checkMaxAppears(t);
}
return calc.getMode();
}
/**
* Work like {@link #mode(Object...)}.
*/
public static Map<Float, Integer> mode(float... numbers) {
Objects.requireNonNull(numbers, "numbers must not be null");
if (numbers.length == 0) {
return new HashMap<>();
}
Arrays.sort(numbers);
ModeCalc<Float> modeCalc = new ModeCalc<Float>(numbers[0]);
for (float t : numbers) {
modeCalc.checkMaxAppears(t);
}
return modeCalc.getMode();
}
/**
* Work like {@link #mode(Object...)}.
*/
public static Map<String, Integer> mode(String... strings) {
Objects.requireNonNull(strings, "strings must not be null");
if (strings.length == 0) {
return new HashMap<>();
}
Arrays.sort(strings);
ModeCalc<String> state = new ModeCalc<>(strings[0]);
for (String t : strings) {
state.checkMaxAppears(t);
}
return state.getMode();
}
private static class ModeCalc<T> {
private int nTimesLastObjectAppears = 0;
private int maxTimeObjectAppears = 0;
private T prevObject;
Map<T, Integer> mostAppearsObjects;
public ModeCalc(T firstObjectInArray) {
prevObject = firstObjectInArray;
mostAppearsObjects = new HashMap<>();
}
void checkMaxAppears(T currentObject) {
if (currentObject.equals(prevObject)) {
nTimesLastObjectAppears += 1;
} else {
addObjectToMap();
prevObject = currentObject;
nTimesLastObjectAppears = 1;
}
}
void addObjectToMap() {
if (nTimesLastObjectAppears > maxTimeObjectAppears) {
mostAppearsObjects.clear();
mostAppearsObjects.put(prevObject, nTimesLastObjectAppears);
maxTimeObjectAppears = nTimesLastObjectAppears;
} else if (nTimesLastObjectAppears == maxTimeObjectAppears) {
mostAppearsObjects.put(prevObject, nTimesLastObjectAppears);
}
}
Map<T, Integer> getMode() {
// to check appears of last object of loop and add it to map
addObjectToMap();
return mostAppearsObjects;
}
}
}
Mapsince the integer values is the same for all of them. Perhaps you can create you own customResultclass that contains a unmodifiableSet<T>of all the mode objects and the common mode frequency. Alternatively Third-party common libraries containTupleorPairto return two values. \$\endgroup\$Arrays.sort(Object[])javadoc map(Object ...) will fail if the user passes objects that do not implementComparableor they are not mutually comparable. \$\endgroup\$Tto beComparable<? super T>to fix that. Thenmap(T ... o)can delegate onmap(Comparator<? super T>, T ... o)by providing a trivial comparator that uses T's owncompareTo. PerhapsComparatorclass has some static to create it. \$\endgroup\$