Link to home
Start Free TrialLog in
Avatar of MarkLoveExEx
MarkLoveExEx

asked on

Arrays.asList VS ArrayList

I have this cool piece of code that picks out the largest outlier of a bunch of Doubles.

It uses Apache Commons math utilities.

The way "getOutlier" is called is via the following:

MathUtil m = new MathUtil();
Double d0 = (Double) m.getOutlier(Arrays.asList(1.1, 2, 5, 8, 14.6, 3, 4, 3), 0.95);

Open in new window


But my project has ArrayLists that I need to pass to it.

If I have an ArrayList, how can I call "m.getOutlier", sending it that ArrayList?
I don't want to call m.getOutlier using the "Arrays.asList(blah blah)" like it does now.

I've messed around with this for a few hours, and just can't seem to make the necessary modifications.

I have attached the full code in a file, and here it is here as well:

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.math.MathException;
import org.apache.commons.math.distribution.TDistributionImpl;
import org.apache.commons.math.stat.StatUtils;

public class MathUtil {
	
	/** static instance */
	private static final MathUtil instance = new MathUtil();
	/** default significance level */
	public static final double DEFAULT_SIGNIFICANCE_LEVEL = 0.95;
	
	public boolean hasOutlier(Object ... values) {
		return hasOutlier(Arrays.asList(values));
	}
	public boolean hasOutlier(List<?> values) {
		return getOutlier(values) != null;
	}

	/** 
	 * Returns a statistical outlier with the default significance level (0.95),
	 * or null if no such outlier exists..
	 */
	public <T> T getOutlier(List<T> values) {
		return getOutlier(values, DEFAULT_SIGNIFICANCE_LEVEL);
	}
	public <T> T getOutlier(List<T> values, double significanceLevel) {
		AtomicReference<T> outlier = new AtomicReference<T>();
		double grubbs = getGrubbsTestStatistic(values, outlier);
		double size = values.size();
		if(size < 3) {
			return null;
		}
		TDistributionImpl t = new TDistributionImpl(size - 2.0);
		try {
			double criticalValue = t.inverseCumulativeProbability((1.0 - significanceLevel) / (2.0 * size));
			double criticalValueSquare = criticalValue * criticalValue;
			double grubbsCompareValue = ((size - 1) / Math.sqrt(size)) * 
					Math.sqrt((criticalValueSquare) / (size - 2.0 + criticalValueSquare));
//commented 12/15/2016
			//			System.out.println("critical value: " + grubbs + " - " + grubbsCompareValue);
			if(grubbs > grubbsCompareValue) {
				return outlier.get();
			} else {
				return null;
			}
		} catch (MathException e) {
			throw new RuntimeException(e);
		}
	}
	/** returns a minimum outlier (if one exists) */
	public <T> T getOutlierMin(List<T> values) {
		T d = getOutlier(values, DEFAULT_SIGNIFICANCE_LEVEL);
		if(d == null)
			return null;
		double d1 = toDouble(d);
		double d2 = toDouble(min(values));
		if(d1 == d2)
			return d;
		return null;
	}
	/** returns a minimum outlier (if one exists) */
	public <T> T getOutlierMax(List<T> values) {
		T d = getOutlier(values, DEFAULT_SIGNIFICANCE_LEVEL);
		if(d == null)
			return null;
		double d1 = toDouble(d);
		double d2 = toDouble(max(values));
		if(d1 == d2)
			return d;
		return null;
	}
	
	public <T> double getGrubbsTestStatistic(List<T> values, AtomicReference<T> outlier) {
		double[] array = toArray(values);
		double mean = StatUtils.mean(array);
		double stddev = stdDev(values);
		double maxDev = 0;
		for(T o : values) {
			double d = toDouble(o);
			if(Math.abs(mean - d) > maxDev) {
				maxDev = Math.abs(mean - d);
				outlier.set(o);
			}
		}
		double grubbs = maxDev / stddev;
//commented 12/15/2016
		//		System.out.println("mean/stddev/maxDev/grubbs: " + mean + " - " + stddev + " - " + maxDev + " - " + grubbs);
		return grubbs;
	}

	private static enum Operator {
		MIN, MAX
	}

	public double sum(Collection<?> c) {
		double s = 0;
		for(Object o : c) {
			s += Double.parseDouble("" + o);
		}
		return s;
	}

	public double average(Collection<?> c) {
		return sum(c) / (double) c.size();
	}
	public double avg(Collection<?> c) {
		return average(c);
	}

	public <T> T min(List<T> values) {
		return executeOp(values, Operator.MIN);
	}
	public <T> T max(List<T> values) {
		return executeOp(values, Operator.MAX);
	}
	public double max(double[] values) {
		return executeOp(asList(values), Operator.MAX);
	}
	public int max(int[] values) {
		return executeOp(asList(values), Operator.MAX);
	}
	public long max(long[] values) {
		return executeOp(asList(values), Operator.MAX);
	}

	private <T> T executeOp(List<T> values, Operator op) {
		double res = op == Operator.MIN ? Double.MAX_VALUE : Double.MIN_VALUE;
		T obj = null;
		for(T o : values) {
			double d = toDouble(o);
			if((op == Operator.MIN && d < res) ||
					(op == Operator.MAX && d > res)){
				res = d;
				obj = o;
			}
		}
		return obj;
	}

	public List<Integer> asList(int[] values) {
		List<Integer> result = new LinkedList<Integer>();
		for(int v : values) {
			result.add(v);
		}
		return result;
	}
	public List<Long> asList(long[] values) {
		List<Long> result = new LinkedList<Long>();
		for(long v : values) {
			result.add(v);
		}
		return result;
	}
	public List<Double> asList(double[] values) {
		List<Double> result = new LinkedList<Double>();
		for(double v : values) {
			result.add(v);
		}
		return result;
	}
		
	public Double stdDev(List<?> values) {
		return stdDev(toArray(values));
	}
	public Double stdDev(double[] values) {
		return Math.sqrt(StatUtils.variance(values));
	}
	
	public Double toDouble(Object o) {
		if(o instanceof Double)
			return (Double)o;
		if(o instanceof Integer)
			return (double)(int)(Integer)o;
		if(o instanceof Long)
			return (double)(long)(Long)o;
		return Double.parseDouble("" + o);
	}
	public List<Double> toDoubles(List<?> values) {
		List<Double> d = new LinkedList<Double>();
		for(Object o : values) {
			double val = toDouble(o);
			d.add(val);
		}
		return d;
	}
	public double[] toArray(List<?> values) {
		double[] d = new double[values.size()];
		int count = 0;
		for(Object o : values) {
			double val = o instanceof Double ? (Double)o : Double.parseDouble("" + o);
			d[count++] = val;
		}
		return d;
	}

	public Integer toInteger(String in) {
		if(in == null)
			return null;
		try {
			return Integer.parseInt(in);
		} catch(Exception e) {
			return null;
		}
	}
	
	public static MathUtil getInstance() {
//		System.out.println(Thread.currentThread().toString() + "-" + Thread.currentThread().getId() + " - " +
//				"MathUtil.getInstance()");
		return instance;
	}

	private static void assertion(boolean value) {
		if(!value)
			throw new RuntimeException("Assertion failed.");
	}
	
	public static void main(String[] args) {
//MY QUESTION FOR EXPERTS-EXCHANGE:
//If I have an ArrayList, how can I call "m.getOutlier", sending it that ArrayList?
//I don't want to call m.getOutlier using the "Arrays.asList(blah blah)" like it does now
 
		MathUtil m = new MathUtil();
		Double d0 = (Double) m.getOutlier(Arrays.asList(1.1, 2, 5, 8, 14.6, 3, 4, 3), 0.95);
		System.out.println(d0);
	}
	
}

Open in new window


Thanks.
getOutlier.java
ASKER CERTIFIED SOLUTION
Avatar of CPColin
CPColin
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of MarkLoveExEx
MarkLoveExEx

ASKER

CPColin,  you set me in the right direction.  It was tough.  This is what I finally ended up doing:

1.) Create a new ArrayList<Double>    (called myArrayList)
2.) Create a new DefaultListModel<Double>    (called myListModel)
3.) Loop through my other (not shown) ArrayList (called myObsArrayList) that contains the data I need, and addElement to the myListModel
4.) Then,   myArrayList = Collections.list(myListModel.elements());
5.) Finally,   Double d0 = (Double) m.getOutlier((List) myArrayList, 0.95);

Whew.  

I'm still getting a warning on step 5, which says, "Type safety: Unchecked invocation getOutlier(List, double) of the generic method getOutlier(List<T>,double) of type MathUtil

But, it still seemed to run ok.

By your suggestion (to pass a List<Double>), I did the casting on Step 5 above, and worked backwards.  I appreciate it.
See comment.  :)
Avatar of mccarl
Depending on exactly what type your "myObsArrayList" is, if you can't just pass it directly (because it's not a List<Double> type) you at least shouldn't have needed to go to quite the lengths you detailed above, definitely shouldn't need the DefaultListModel stuff. Something like the below should have been enough to get you going (and get rid of your warning)...

List<Double> myList = new ArrayList<Double>();
for (Object value : myObsArrayList) {               // Or however you looped through your original array (i.e. exactly the same loop as in step 3 above)
    myList.add(value);                                         // The myList.add is right, but change the value you are passing it to, again, whatever you did in step 3
}
Double d0 = m.getOutlier(myList, 0.95);            // No casts should be necessary, and no warnings should be given

Open in new window