views:

77

answers:

3

I have to pass a primitive 2d array to a filtering routine.The algorithm for filtering(median filter) is same irrespective of the type of the array.Is there a way to pass any type of array in a generic manner or should I overload the same same function with different array types.In the second case the same code will have to be repeated for different data types.

int[][] medianfilter(int[][] arr){ ... }
float[][] medianfilter(float[][] arr){ ... }

Is there a way to make the above code a generic one,instead of repeating the code for medianfilter in each an every overloaded function ?

+1  A: 

The only way to pass it in a generic manner and keep it as a primitive array is as an Object. Personally, I'd just overload it, and see it as a cost of using primitives.

To avoid duplication of code in the algorithm (if it is a lot of code) you could produce an abstract class called something like DoubleAlgorithm with abstract methods like double getElement(int i, int j) and handleResult(double result) and then write very small subclasses of this, one for each primitive type.

Let me explain with an example (suppose the algorithm was adding the numbers).

public int filter(int [][] values) {
   IntAlgorithm algo = new IntAlgorithm(values);
   algo.run();
   return algo.getResult();
}
public double filter(double [][] values) {
   DoubleAlgorithm algo = new DoubleAlgorithm(values);
   algo.run();
   return algo.getResult();
}

public class AbstractAlgorithm {
  public  run() {
     double sum = 0.0;
     for(int i=0; i<rows(); i++) {
       for(int j=0; j<columns(i); j++) {
          sum+=getElement(i, j);
       }
     }
     handleResult(sum);
  }
  protected abstract int rows();
  protected abstract int columns(int row);
  protected abstract double getElement(int i, int j);
  protected abstract void handleResult();
}

public class IntAlgorithm extends AbstractAlgorithm {
    int [][] values;
    int result;
    IntAlgorithm(int [][] values) {
       this.values= values;
    }
    public int rows() {
      return values.length;
    }
    public int columns(int row) {
      return values[row].length;
    }
    public double getElement(int i, int j) {
      return values[i][j];
    }
    public void handleResult(double result) {
      this.result = (int)result;
    }
    public int getResult() {
      return result;
    }
}

As you can see, it is quite verbose, but if your algorithm was big it might be worth it. Hopefully it is obvious how to extend to your algorithm.

As Thilo has pointed out, it isn't safe to do all algorithms with just treating ints/longs as doubles, but for a number it will be good enough. If it isn't for you, then you need to go even more verbose, work out which properties of numbers you need (eg add) and extract those to a separate interface. For a median filter, I would expect just using doubles will work fine, but I'd test the edge cases.

Nick Fortescue
He could pass it in as Object[] (with one dimension)
Thilo
Can you please give a code sample for second part of your suggestion?
jayakumar
done. I haven't even compiled this, but hopefully you get the idea
Nick Fortescue
not so sure I would want to do the actual calculations for int[] and long[] in double.
Thilo
if he wants to avoid repeating the code he has to do them in double, unless he starts using a "Summable" interface or similar, and it gets even more complicated. Whether doing int or long calculations as a double is ok depends on the algorithm, I would expect in most cases for a median filter it would be fine
Nick Fortescue
+1  A: 

There is no good way to do this for primitive arrays, which is why all the library functions (such as java.util.Arrays) also have these duplicated methods.

You could define a method

Object[] medianfilter(Object[] arr); // note the missing dimension

and use reflection to find out the runtime type. This is what System.arraycopy is doing. But you then need to type-cast. Ugly.

int[][]  result = (int[][]) medianFilter( input );

Go with the duplicated methods.

Thilo
Scratch the last sentence, I hate those duplicates :-) +1
seanizer
Even better: Don't write duplicate code, write a script that does it for you. Ideally, you'd have it auto-generated for you as part of the build process, but I guess this isn't code that'll change particularly often, so running the script manually every time you change an implementation detail probably isn't all that bad.
gustafc
Don't mess with your build process unless absolutely necessary.
Thilo
+1  A: 

There is a way to pass the type of an array in a generic manner:

public T test(T[][] arg)
{
    T[][] q = arg;
    T[]   r = q[0];
    T     s = r[0];

    return s;
}

... unfortunately it won't work for primitive types. You'll need to use Integer and Float as your parameterized types.

richj