student
student

Reputation: 5

How to apply a function to an array element wise in Java?

Let's say I have 3 functions, something like y_1(x) = x^2, y_2(x) = x+1 and y_3(x) = x/5. How do I apply these functions to any multidimensional float array in an element wise fashion?

Now given that I have the functions y_1, y_2 and y_3, what is a function that applies an arbitrary function to a float array of any size and shape?

I tried creating a function applier that takes in any function and then applying it to every element in a double loop for the 2 dimensional case but I cannot even get the function applier to take another function as input.

I tried doing the following

public float[][] elemen_wise_function(  float[][] x,
                                        int Size_axis_0,
                                        int Size_axis_1,
                                        Callable<> myFunc) {

    float[][] Constructed_array = new float[Size_axis_0][Size_axis_1];
    for (int i=0; i<Size_axis_0; i++) {
        for (int j = 0; j < Size_axis_1; j++) {
            Constructed_array[i][j] = (float) myFunc(x[i][j]) ;
        }
    }
    return Constructed_array;
}

But this fails because I cannot find a way to pass myFunc to elemen_wise_function.

Upvotes: 0

Views: 4719

Answers (3)

user104729
user104729

Reputation: 58

If you are trying to do this with Java 6, you can do something like.

    import java.util.Arrays;
    import java.util.function.Function;

    public interface MapFunction {
        public float map(float value);
    }

    public static float[][] map2DArray(float[][] floatArrays, MapFunction mapper) {
        final float[][] retval = new float[floatArrays.length][];
        for (int i = 0; i < floatArrays.length; i++) {
            float [] floats = floatArrays[i];
            retval[i] = new float[floats.length];
            for (int j = 0; j < floats.length; j++) {
                retval[i][j] = mapper.map(floats[j]);
            }
        }
        return retval;
    }

Or in Java 8 and you don't mind using Float

    import java.util.Arrays;
    import java.util.function.Function;

    public static Float[][] map2DArray(Float[][] floatArrays, Function<Float, Float> mapper) {
        return Arrays.stream(floatArrays).map((Float[] floats) -> 
                Arrays.stream(floats).map(mapper).toArray(Float[]::new)
        ).toArray(Float[][]::new);
    }

Upvotes: 0

Andronicus
Andronicus

Reputation: 26056

Quite cool, you can pass a lambda (since java 8):

public float[][] elemen_wise_function(float[][] x,
                                      Function<Float, Float> f) {

    float[][] Constructed_array = new float[x.length][x[0].length];
    for (int i=0; i<x.length; i++) {
        for (int j = 0; j < x[0].length; j++) {
            Constructed_array[i][j] = f.apply(x[i][j]);
        }
    }
    return Constructed_array;
}

Then you can pass any function defined as lambda, for example:

Function<Float, Float> fun = x -> 2 * x;

Also one note - use camelCase in java for method names;)

Upvotes: 0

rustyx
rustyx

Reputation: 85452

One solution would be to declare myFunc as UnaryOperator<Float>.

public float[][] elemen_wise_function(float[][] x, int Size_axis_0, int Size_axis_1,
                                      UnaryOperator<Float> myFunc) {

Unfortunately that will autobox the float back and forth.

If performance is a concern you can define a custom interface that is hard-coded to operate on primitive floats:

interface FloatOperator {
    float apply(float x);
}

public float[][] elemen_wise_function(float[][] x, int Size_axis_0, int Size_axis_1,
                                      FloatOperator myFunc) {

In both cases use as:

    for (int i = 0; i < Size_axis_0; i++) {
        for (int j = 0; j < Size_axis_1; j++) {
            Constructed_array[i][j] = myFunc.apply(x[i][j]);
        }
    }

Invoke as (example):

    elemen_wise_function(array, size0, size1, a -> 1/a);

Upvotes: 2

Related Questions