/src/main/java/net/triptech/metahive/KeyValueIdentifier.java
https://github.com/stressfree/metahive · Java · 616 lines · 346 code · 88 blank · 182 comment · 106 complexity · 1653b99f0b729b6b224902d5b0ddbde6 MD5 · raw file
- /*******************************************************************************
- * Copyright (c) 2012 David Harrison, Triptech Ltd.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Public License v3.0
- * which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/gpl.html
- *
- * Contributors:
- * David Harrison, Triptech Ltd - initial API and implementation
- ******************************************************************************/
- package net.triptech.metahive;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.TreeMap;
- import net.triptech.metahive.model.KeyValueBoolean;
- import org.apache.commons.lang.StringUtils;
- /**
- * The Class KeyValueIdentifier.
- */
- public class KeyValueIdentifier {
- /**
- * Calculate the key value based on the newest value.
- *
- * @param values the values
- * @return the object
- */
- public static Object newest(final List<Object> values) {
- Object keyValue = null;
- if (values != null && values.size() > 0) {
- keyValue = values.get(values.size() - 1);
- }
- return keyValue;
- }
- /**
- * Calculate the key value based on the oldest value.
- *
- * @param values the values
- * @return the object
- */
- public static Object oldest(final List<Object> values) {
- Object keyValue = null;
- if (values != null && values.size() > 0) {
- keyValue = values.get(0);
- }
- return keyValue;
- }
- /**
- * Calculate the key value based on the most frequent (default to newest if none).
- *
- * @param values the values
- * @return the object
- */
- public static Object frequentDefaultNewest(final List<Object> values) {
- Object keyValue = frequent(values);
- if (keyValue == null) {
- keyValue = newest(values);
- } else {
- if (keyValue instanceof String && StringUtils.isBlank((String) keyValue)) {
- keyValue = newest(values);
- }
- }
- return keyValue;
- }
- /**
- * Calculate the key value based on the most frequent (default to oldest if none).
- *
- * @param values the values
- * @return the object
- */
- public static Object frequentDefaultOldest(final List<Object> values) {
- Object keyValue = frequent(values);
- if (keyValue == null) {
- keyValue = oldest(values);
- } else {
- if (keyValue instanceof String && StringUtils.isBlank((String) keyValue)) {
- keyValue = oldest(values);
- }
- }
- return keyValue;
- }
- /**
- * Calculate the key value by concatenating the values.
- *
- * @param values the values
- * @return the object
- */
- public static Object concat(final List<Object> values) {
- Object keyValue = null;
- TreeMap<String, Integer> valueSet = new TreeMap<String, Integer>();
- for (Object value : values) {
- if (value instanceof String) {
- valueSet.put((String) value, 0);
- }
- }
- if (valueSet.size() > 0) {
- StringBuilder sb = new StringBuilder();
- int count = valueSet.keySet().size();
- int counter = 1;
- for (String item : valueSet.keySet()) {
- if (sb.length() > 0) {
- if (counter == count) {
- sb.append(" and ");
- } else {
- sb.append(", ");
- }
- }
- sb.append(item);
- counter++;
- }
- keyValue = sb.toString();
- }
- return keyValue;
- }
- /**
- * Calculate the key value based on what value is unanimous.
- * If there is any conflict then the result is unclear.
- * This is only applicable to boolean type key values.
- *
- * @param values the values
- * @return the object
- */
- public static Object unclear(final List<Object> values) {
- KeyValueBoolean keyValue = null;
- boolean unclearKeyValue = false;
- for (Object value : values) {
- if (value instanceof KeyValueBoolean) {
- if (keyValue == null) {
- keyValue = (KeyValueBoolean) value;
- }
- if (keyValue != (KeyValueBoolean) value) {
- // Mismatch - default to unclear
- unclearKeyValue = true;
- }
- }
- }
- if (unclearKeyValue) {
- // Reset key value to unclear
- keyValue = KeyValueBoolean.BL_UNCLEAR;
- }
- return keyValue;
- }
- /**
- * Calculate the median value from the list of supplied values.
- * This assumes that the list of values are Double or KeyValueBoolean objects.
- * If no Double or KeyValueBoolean objects exist then null is returned.
- *
- * @param values the values
- * @return the object
- */
- public static Object median(final List<Object> values) {
- Object keyValue = null;
- if (values.size() > 0) {
- if (values.get(0) instanceof Double) {
- ArrayList<Double> sortedList = parseToSortedDoubleList(values);
- if (sortedList.size() > 0) {
- keyValue = getMedian(sortedList);
- }
- }
- if (values.get(0) instanceof KeyValueBoolean) {
- // Parse the list of doubles to a list of:
- // twos (true), ones (unclear), and zeros (false)
- List<Object> doubleValues = new ArrayList<Object>();
- for (Object object : values) {
- if (object instanceof KeyValueBoolean) {
- doubleValues.add(parseBooleanToDouble(object));
- }
- }
- ArrayList<Double> sortedList = parseToSortedDoubleList(doubleValues);
- if (sortedList.size() > 0) {
- keyValue = parseDoubleToBoolean(getMedian(sortedList));
- }
- }
- }
- return keyValue;
- }
- /**
- * Calculate the lower quartile value from the list of supplied values.
- * This assumes that the list of values are Double or KeyValueBoolean objects.
- * If no Double or KeyValueBoolean objects exist then null is returned.
- *
- * @param values the values
- * @return the object
- */
- public static Object quartileLower(final List<Object> values) {
- Object keyValue = null;
- if (values.size() > 0) {
- if (values.get(0) instanceof Double) {
- ArrayList<Double> sortedList = parseToSortedDoubleList(values);
- if (sortedList.size() > 0) {
- keyValue = getQuartileLower(sortedList);
- }
- }
- if (values.get(0) instanceof KeyValueBoolean) {
- // Parse the list of doubles to a list of:
- // twos (true), ones (unclear), and zeros (false)
- List<Object> doubleValues = new ArrayList<Object>();
- for (Object object : values) {
- if (object instanceof KeyValueBoolean) {
- doubleValues.add(parseBooleanToDouble(object));
- }
- }
- ArrayList<Double> sortedList = parseToSortedDoubleList(doubleValues);
- if (sortedList.size() > 0) {
- keyValue = parseDoubleToBoolean(getQuartileLower(sortedList));
- }
- }
- }
- return keyValue;
- }
- /**
- * Calculate the upper quartile value from the list of supplied values.
- * This assumes that the list of values are Double or KeyValueBoolean objects.
- * If no Double or KeyValueBoolean objects exist then null is returned.
- *
- * @param values the values
- * @return the object
- */
- public static Object quartileUpper(final List<Object> values) {
- Object keyValue = null;
- if (values.size() > 0) {
- if (values.get(0) instanceof Double) {
- ArrayList<Double> sortedList = parseToSortedDoubleList(values);
- if (sortedList.size() > 0) {
- keyValue = getQuartileUpper(sortedList);
- }
- }
- if (values.get(0) instanceof KeyValueBoolean) {
- // Parse the list of doubles to a list of:
- // twos (true), ones (unclear), and zeros (false)
- List<Object> doubleValues = new ArrayList<Object>();
- for (Object object : values) {
- if (object instanceof KeyValueBoolean) {
- doubleValues.add(parseBooleanToDouble(object));
- }
- }
- ArrayList<Double> sortedList = parseToSortedDoubleList(doubleValues);
- if (sortedList.size() > 0) {
- keyValue = parseDoubleToBoolean(getQuartileUpper(sortedList));
- }
- }
- }
- return keyValue;
- }
- /**
- * Calculate the total value from the list of supplied values.
- * This assumes that the list of values are Double objects.
- * If no Double objects exist in the values list then null is returned.
- *
- * @param values the values
- * @return the object
- */
- public static Object total(final List<Object> values) {
- Double keyValue = null;
- double runningTotal = 0;
- boolean valueSet = false;
- for (Object value : values) {
- if (value instanceof Double) {
- runningTotal += (Double) value;
- valueSet = true;
- }
- }
- if (valueSet) {
- // At least one valid Double value existed
- keyValue = runningTotal;
- }
- return keyValue;
- }
- /**
- * Calculate the average value from the list of supplied values.
- * This assumes that the list of values are Double objects.
- * If no Double objects exist in the values list then null is returned.
- *
- * @param values the values
- * @return the object
- */
- public static Object average(final List<Object> values) {
- Double keyValue = null;
- double runningTotal = 0;
- int count = 0;
- for (Object value : values) {
- if (value instanceof Double) {
- runningTotal += (Double) value;
- count++;
- }
- }
- if (count > 0) {
- // At least one valid Double value existed
- keyValue = runningTotal / count;
- }
- return keyValue;
- }
- /**
- * Calculate the highest value from the list of supplied values.
- * This assumes that the list of values are Double objects.
- * If no Double objects exist in the values list then null is returned. *
- *
- * @param values the values
- * @return the object
- */
- public static Object highest(final List<Object> values) {
- Double keyValue = null;
- ArrayList<Double> sortedList = parseToSortedDoubleList(values);
- if (sortedList.size() > 0) {
- keyValue = sortedList.get(sortedList.size() - 1);
- }
- return keyValue;
- }
- /**
- * Calculate the lowest value from the list of supplied values.
- * This assumes that the list of values are Double objects.
- * If no Double objects exist in the values list then null is returned. *
- *
- * @param values the values
- * @return the object
- */
- public static Object lowest(final List<Object> values) {
- Double keyValue = null;
- ArrayList<Double> sortedList = parseToSortedDoubleList(values);
- if (sortedList.size() > 0) {
- keyValue = sortedList.get(0);
- }
- return keyValue;
- }
- /**
- * Calculate the most frequent key value.
- *
- * @param values the values
- * @return the object
- */
- private static Object frequent(final List<Object> values) {
- Object keyValue = null;
- Map<String, Integer> hitCount = new HashMap<String, Integer>();
- Map<String, Object> originalCap = new HashMap<String, Object>();
- int maxHitCount = 0;
- if (values != null && values.size() > 0) {
- for (Object objValue : values) {
- String value = parseToString(objValue);
- int count = 0;
- if (!hitCount.containsKey(value.toUpperCase())) {
- originalCap.put(value.toUpperCase(), objValue);
- } else {
- count = hitCount.get(value.toUpperCase());
- }
- count++;
- if (count > maxHitCount) {
- maxHitCount = count;
- }
- hitCount.put(value.toUpperCase(), count);
- }
- }
- boolean keyValueSet = false;
- for (String valueKey : hitCount.keySet()) {
- int count = hitCount.get(valueKey);
- if (count == maxHitCount) {
- if (!keyValueSet) {
- keyValue = originalCap.get(valueKey);
- } else {
- // Invalidate the keyValue because there is a duplicate most frequent
- keyValue = null;
- }
- }
- }
- return keyValue;
- }
- /**
- * Parses the object value to a string.
- *
- * @param objValue the value as an object
- * @return the string
- */
- private static String parseToString(final Object objValue) {
- String value = "";
- if (objValue != null) {
- if (objValue instanceof String) {
- value = (String) objValue;
- }
- if (objValue instanceof Double) {
- value = String.valueOf((Double) objValue);
- }
- }
- return value;
- }
- /**
- * Parse the value list into a sorted double list.
- *
- * @param values the values
- * @return the array list
- */
- private static ArrayList<Double> parseToSortedDoubleList(final List<Object> values) {
- ArrayList<Double> list = new ArrayList<Double>();
- for (Object value : values) {
- if (value instanceof Double) {
- list.add((Double) value);
- }
- }
- Collections.sort(list);
- return list;
- }
- /**
- * Gets the median value from the sorted list of doubles.
- *
- * @param sortedList the sorted list
- * @return the median
- */
- private static double getMedian(final List<Double> sortedList) {
- double median = 0;
- if (sortedList.size() % 2 == 1) {
- median = sortedList.get((sortedList.size() + 1) / 2 - 1);
- } else {
- double lower = sortedList.get(sortedList.size() / 2 - 1);
- double upper = sortedList.get(sortedList.size() / 2);
- median = (lower + upper) / 2.0;
- }
- return median;
- }
- /**
- * Gets the lower quartile value.
- *
- * @param sortedList the sorted list
- * @return the quartile lower
- */
- private static double getQuartileLower(final List<Double> sortedList) {
- double quartileLower = 0;
- if (sortedList.size() > 3) {
- double median = getMedian(sortedList);
- quartileLower = getMedian(getValuesLessThan(sortedList, median));
- } else {
- // If less than three values return the first (lowest) value
- quartileLower = sortedList.get(0);
- }
- return quartileLower;
- }
- /**
- * Gets the upper quartile value.
- *
- * @param sortedList the sorted list
- * @return the quartile upper
- */
- private static double getQuartileUpper(final List<Double> sortedList) {
- double quartileUpper = 0;
- if (sortedList.size() > 3) {
- double median = getMedian(sortedList);
- quartileUpper = getMedian(getValuesGreaterThan(sortedList, median));
- } else {
- // If less than three values return the last (highest) value
- quartileUpper = sortedList.get(sortedList.size() - 1);
- }
- return quartileUpper;
- }
- /**
- * Gets the values greater than the supplied limit.
- *
- * @param values the values
- * @param limit the limit
- * @return the values greater than the supplied limit
- */
- private static List<Double> getValuesGreaterThan(final List<Double> values,
- final double limit) {
- List<Double> modValues = new ArrayList<Double>();
- for (double value : values) {
- if (value > limit || (value == limit)) {
- modValues.add(value);
- }
- }
- return modValues;
- }
- /**
- * Gets the values less than the supplied limit.
- *
- * @param values the values
- * @param limit the limit
- * @return the values less than the supplied limit
- */
- public static List<Double> getValuesLessThan(final List<Double> values,
- final double limit) {
- List<Double> modValues = new ArrayList<Double>();
- for (double value : values) {
- if (value < limit || (value == limit)) {
- modValues.add(value);
- }
- }
- return modValues;
- }
- /**
- * Parses the KeyValueBoolean to a double.
- *
- * @param bl the bl
- * @return the double
- */
- private static double parseBooleanToDouble(final Object object) {
- double value = 1;
- if (object instanceof KeyValueBoolean) {
- KeyValueBoolean bl = (KeyValueBoolean) object;
- if (bl == KeyValueBoolean.BL_TRUE) {
- value = 2;
- }
- if (bl == KeyValueBoolean.BL_UNCLEAR) {
- value = 1;
- }
- if (bl == KeyValueBoolean.BL_FALSE) {
- value = 0;
- }
- }
- return value;
- }
- /**
- * Parses the double to a KeyValueBoolean.
- *
- * @param value the value
- * @return the key value boolean
- */
- private static KeyValueBoolean parseDoubleToBoolean(final Double value) {
- KeyValueBoolean bl = KeyValueBoolean.BL_UNCLEAR;
- if (value == 2) {
- bl = KeyValueBoolean.BL_TRUE;
- }
- if (value == 1) {
- bl = KeyValueBoolean.BL_UNCLEAR;
- }
- if (value == 0) {
- bl = KeyValueBoolean.BL_FALSE;
- }
- return bl;
- }
- }