0

I have a method which takes variable number and types of arguments in the form of Object. I want to calculate the median of only the numbers in those arguments. I used Lists to insert the elements(numbers) and then Collections to sort the List. I am getting a Classcast exception in Collections.sort() line whenever I am passing integers along with doubles as arguments. Here is my method:

public Object median(Object... O) {

    List l = new ArrayList<Object>();
    for (int i = 0; i < O.length; i++) {
        if (Number.class.isAssignableFrom(O[i].getClass())) {
            l.add(O[i]);
        } else {
            try {
                double d = Double.parseDouble(O[i].toString());
                l.add(d);
            } catch (Exception e) {

            }
        }
    }
    Collections.sort(l);
    double sum = 0;
    if (l.size() % 2 == 0) {

        if (l.get((l.size()) / 2 - 1) instanceof Double) {
            Double d = (Double) l.get((l.size()) / 2 - 1);
            sum += d;
        } else if (l.get((l.size()) / 2 - 1) instanceof Integer) {
            Integer d = (Integer) l.get((l.size()) / 2 - 1);
            sum += d;
        }
        if (l.get((l.size()) / 2) instanceof Double) {
            Double d1 = (Double) l.get(l.size() / 2);
            sum += d1;
        } else if (l.get((l.size()) / 2) instanceof Integer) {
            Integer d1 = (Integer) l.get(l.size() / 2);
            sum += d1;
        }

        return sum / 2;
    } else {
        if (l.get((l.size()) / 2) instanceof Double) {
            Double d1 = (Double) l.get(l.size() / 2);
            sum = d1;
        } else if (l.get((l.size()) / 2) instanceof Integer) {
            Integer d1 = (Integer) l.get(l.size() / 2);
            sum = d1;
        }
        return sum;
       }

    }

I can call the method in any way like :

  1. System.out.println("Median---------"+cmp.median(13, 18, 13, 14, 13, 16, 14, 21, 13));

  2. System.out.println("Median---------"+cmp.median(13, 18.1, 13, 14, 13, 16, 14, 21, 13));

  3. System.out.println("Median---------"+cmp.median(13, 18, 13,"13", 14, 13, 16, 14, 21,13);

  4. System.out.println("Median---------"+cmp.median(13, 18,"xyz", 13, 14, 13, 16, 14,21,13));

I think Collections.sort() cant work with Doubles. Please suggest a way out!

Parijat Bose
  • 380
  • 1
  • 6
  • 22

4 Answers4

1

Convert

List l = new ArrayList<Object>();

to

List<Number> l = new ArrayList<Number>();

And use: Inside the for loop, have:

if(O[i] instanceof Number)
   l.add((Number)O[i]);

And to sort them:

Collections.sort(l, new Comparator<Number>(){
 @Override
  public void compare(Number t1, Number t2){
   if(t1.doubleValue<t2.doubleValue)
    return -1;
    else if(t1.doubleValue==t2.doubleValue)
       return 0 
    else return 1
}
}

It correctly throws ClassCastException as the l defined is a list of type Object. As per declaration Object does not implement Comparable. Hence you need to give a comparator which does the job

Jatin
  • 31,116
  • 15
  • 98
  • 163
  • What Object ? Some Custom Class object ? – AllTooSir Apr 15 '13 at 11:50
  • since in your solution List is of Number type so List l cannot add a Object – Parijat Bose Apr 15 '13 at 12:16
  • u need to check the type of the Obejct, I have edited it. Only if it is Number, add it to the list – Jatin Apr 15 '13 at 12:17
  • You cant add directly an Object to the List without converting the Object to Number... – Parijat Bose Apr 15 '13 at 12:20
  • Of-course you can't. If they are strictly of typep Objects, then there does not exist any solution. Given that there exists numebrs hidden in obejct array, we search for te obejcts which are number, type-cast them and add. Edited – Jatin Apr 15 '13 at 12:23
0

I guess the issue is with your else block.

If your control flow goes to else then it means that the object is not a number (double or other wise) and hence it is not prudent to add it to the list at all.

Also in your If block you should probably differentiate between various kinds of numbers i.e. Integer, Double etc. and accordingly do the casting.

prashant
  • 1,805
  • 12
  • 19
0

I'd do something like:

public Object median(Object... objs) {
  List<Number> nrs = extractNumbers(objs);
  // do whatever with the numbers
}

private List<Number> extractNumbers(Object[] objs) {
   final List<Number> nrs = new ArrayList<Number>();
   for(final Object o:objs){
      if(isNumber(o)){
        nrs.add(getNumber(o));
      }
   }
   return nrs;
}
private boolean isNumber(Object o){
  Number.class.isAssignableFrom(o.getClass());
}
private Number getNumber(Object o){
  return (Number) o;
}

And then you can modify the isNumber / getNumber methods to fit your identification / parsing needs, without affecting the rest of the algorithm

Matyas
  • 13,473
  • 3
  • 60
  • 73
0

Method to find median of any number and type of arguments

@Override
public Object median(Object... O) {
    List<Double> l = new ArrayList<Double>();
    for (int i = 0; i < O.length; i++) {
        if (Number.class.isAssignableFrom(O[i].getClass())) {
            if (O[i] instanceof Double) {
                Double d = (Double) O[i];
                l.add(d);

            } else if (O[i] instanceof Integer) {
                Integer j = (Integer) O[i];
                double d = Double.parseDouble(Integer.toString(j));
                l.add(d);
            }
        } else {
            try {
                double d = Double.parseDouble(O[i].toString());
                l.add(d);
            } catch (Exception e) {

            }
        }
    }
    Double[] array = new Double[(l.size())];
    l.toArray(array);
    Arrays.sort(array);
    double sum = 0;
    if (array.length % 2 == 0) {

        sum = array[array.length / 2 - 1] + array[array.length / 2];

        return sum / 2;
    } else {

        return array[array.length / 2];
    }

}
Parijat Bose
  • 380
  • 1
  • 6
  • 22