Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the sum of two n-dimensional arrays in Java?

Adding two n-dimensional arrays in Java

addVectors

Two 1-dimensional arrays / vectors in Java can be added like this:

public static int[] addVectors( int[] a, int[] b )
{
    int[] c = new int[a.length];

    for ( int i = 0; i < a.length; i++ )
    {
        c[i] = a[i] + b[i];
    }

    return c;
}

addMatrices

Two 2-dimensional arrays / matrices in Java can be added like this:

public static int[][] addMatrices( int[][] a, int[][] b )
{
    int[][] c = new int[a.length][a[0].length];

    for ( int i = 0; i < a.length; i++ )
    {
        c[i] = addVectors( a[i], b[i] );
    }

    return c;
}

Both functions require the arrays to be of the same size to avoid an arrayOutOfBoundsException.

addArraysN

There should be a way to add two arrays of unknown dimension using recursion.
For example, the following code using the hypothetical function addArraysN( arr1, arr2 )

int[][][] a = { 
                { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } },
                { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } },
                { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }
              };
int[][][] b = { 
                { { 2, 2, 2 }, { 2, 2, 2 }, { 2, 2, 2 } },
                { { 2, 2, 2 }, { 2, 2, 2 }, { 2, 2, 2 } },
                { { 2, 2, 2 }, { 2, 2, 2 }, { 2, 2, 2 } }
              };
int[][][] sum = addArraysN( a, b );
System.out.println( java.util.Arrays.deepToString( sum ) );

should output

[[[3, 3, 3], [3, 3, 3], [3, 3, 3]], [[3, 3, 3], [3, 3, 3], [3, 3, 3]], [[3, 3, 3], [3, 3, 3], [3, 3, 3]]]

Now I'm wondering about how to implement this function addArraysN( arr1, arr2 ).
I started out with the following pseudo code:

addArraysN( arr1, arr2 )
{
    int dimension = getDimension( arr1 );
    if ( dimension == 0 ) //there are no arrays, only numbers
        return arr1 + arr2;
    else
    {
        //create a new arrays with the same dimension and size as arr1 / arr2
        //loop through the fields with for
            //call itself when adding the fields of arr1 and arr2
        //return the sum
    }
}

New arrays can be created using the newInstance-method from java.lang.reflect.Array.
Looping can be made possible like this:

for ( int i = 0; i < ((int[])arr1).length; i++ )
    sum = addArraysN( ((int[])arr1)[i], ((int[])arr2)[i] );

Question

But I stumbled over a lot of runtime errors and other problems. Has anybody an idea or even a solution on how to implement this addArrayN-method?

It should be also possible to work with ArrayList or any other Class but I'm mainly interested on how to do this with arrays... (Nevertheless if someone knows it please post!)

Thanks in advance

appendix 1

My original code:

import java.util.Arrays;
import java.lang.reflect.Array;

public class ArrayN
{
    public static void main( String[] args )
    {
        //Vector
        int[] vector1 = {0, 1, 2, 3, 4};
        int[] vector2 = {4, 3, 2, 1, 0};

        int[] vector3 = ArrayN.addVectors( vector1, vector2 );

        for ( int num : vector3 )
        {
            System.out.print( num );
        }
        System.out.println();

        System.out.println();

        //Matrix
        int[][] matrix1 = {{0, 1, 2, 3, 4}, {4, 3, 2, 1, 0}};
        int[][] matrix2 = {{4, 3, 2, 1, 0}, {0, 1, 2, 3, 4}};

        int[][] matrix3 = ArrayN.addMatrices( matrix1, matrix2 );

        for ( int[] vector : matrix3 )
        {
            for ( int num : vector )
            {
                System.out.print( num );
            }
            System.out.println();
        }

        System.out.println();

        //N-Array

        System.out.println( Arrays.deepToString( (Object[])ArrayN.addArraysN( (Object)matrix1, (Object)matrix2, 2, 5 ) ) );

    }

    public static int[] addVectors( int[] a, int[] b )
    {
        int[] c = new int[a.length];

        for ( int i = 0; i < a.length; i++ )
        {
            c[i] = a[i] + b[i];
        }

        return c;
    }

    public static int[][] addMatrices( int[][] a, int[][] b )
    {
        int[][] c = new int[a.length][a[0].length];

        for ( int i = 0; i < a.length; i++ )
        {
            c[i] = ArrayN.addVectors( a[i], b[i] );
        }

        return c;
    }

    public static Object addArraysN( Object arrayN1, Object arrayN2, int dimension, int innerlength )
    {
        if ( dimension == 0 )
        {
            return (int)arrayN1 + (int)arrayN2;
        }
        else
        {
            int[] dimensions = new int[dimension];
            for ( int i = 0; i < dimension; i++ )
            {
                dimensions[i] = innerlength;
            }
            Object arrayN3 = Array.newInstance( Array.class, dimensions );
            for ( int i = 0; i < Array.getLength( arrayN1 ); i++ )
            {
                Array.set( arrayN3, i, ArrayN.addArraysN( Array.get( arrayN1, i ), Array.get( arrayN2, i ), dimension-1, innerlength ) );
            }

            return arrayN3;
        }
    }
}

Output:

44444

44444
44444

Exception in thread "main" java.lang.IllegalArgumentException: array element type mismatch
    at java.lang.reflect.Array.set(Native Method)
    at ArrayN.addArraysN(ArrayN.java:85)
    at ArrayN.addArraysN(ArrayN.java:85)
    at ArrayN.main(ArrayN.java:41)

appendix 2

I've found the error. It was the following line:

Object arrayN3 = Array.newInstance( Array.class, dimensions );

I had to replace Array.class with int.class. The corrected line should be:

Object arrayN3 = Array.newInstance( int.class, dimensions );

Now I realized another problem the code has:
Every array in the multidimensional array has to be of the same size because of the innerlength argument. If arrays are shorter the other values become zero:

44444

44444
44444

[[4, 4, 4, 4, 4], [4, 4, 4, 4, 4], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

So I first made matrix1 and matrix2 a bit longer:

//Matrix
int[][] matrix1 = {{0, 1, 2, 3, 4}, {4, 3, 2, 1, 0}, {0, 1, 2, 3, 4}, {4, 3, 2, 1, 0}, {0, 1, 2, 3, 4}};
int[][] matrix2 = {{4, 3, 2, 1, 0}, {0, 1, 2, 3, 4}, {4, 3, 2, 1, 0}, {0, 1, 2, 3, 4}, {4, 3, 2, 1, 0}};

But that's not a good solution.
Nikoloz wrote a method to find out the dimensions of arrays. Using it and another method arrayToString( Object ) I wrote my final code is now:

import java.util.Arrays;
import java.lang.reflect.Array;
import java.util.List;
import java.util.ArrayList;

public class ArrayN
{
    public static void main( String[] args )
    {
        int[][] matrix1 = {{0, 1, 2, 3, 4}, {4, 3, 2, 1, 0}};
        int[][] matrix2 = {{4, 3, 2, 1, 0}, {0, 1, 2, 3, 4}};

        System.out.println( ArrayN.arrayToString( ArrayN.addArraysN( matrix1, matrix2 ) ) );

    }

    public static Object addArraysN( Object arrayN1, Object arrayN2 )
    {
        ArrayList<Integer> dimensions = new ArrayList<Integer>();
        ArrayN.getDimensions( arrayN1, dimensions );
        int[] dims = new int[dimensions.size()];
        for ( int i = 0; i < dims.length; i++ )
        {
            dims[i] = dimensions.get( i );
        }

        if ( dims.length == 0 )
        {
            return (int)arrayN1 + (int)arrayN2;
        }
        else
        {
            Object arrayN3 = Array.newInstance( int.class, dims );
            for ( int i = 0; i < Array.getLength( arrayN1 ); i++ )
            {
                Array.set( arrayN3, i, ArrayN.addArraysN( Array.get( arrayN1, i ), Array.get( arrayN2, i ) ) );
            }

            return arrayN3;
        }
    }

    public static void getDimensions( Object array, List<Integer> dimensions )
    {
        if ( array != null && array.getClass().isArray() )
        {
            dimensions.add( Array.getLength( array ) );
            if ( Array.getLength( array ) > 0)
            {
                ArrayN.getDimensions( Array.get( array, 0 ), dimensions );
            }
        }
    }

    public static String arrayToString( Object arr )
    {
        if ( arr instanceof byte[] )
            return Arrays.toString( (byte[])arr );
        else if ( arr instanceof short[] )
            return Arrays.toString( (short[])arr );
        else if ( arr instanceof int[] )
            return Arrays.toString( (int[])arr );
        else if ( arr instanceof long[] )
            return Arrays.toString( (long[])arr );
        else if ( arr instanceof float[] )
            return Arrays.toString( (float[])arr );
        else if ( arr instanceof double[] )
            return Arrays.toString( (double[])arr );
        else if ( arr instanceof char[] )
            return Arrays.toString( (char[])arr );
        else if ( arr instanceof boolean[] )
            return Arrays.toString( (boolean[])arr );
        else
            return Arrays.deepToString( (Object[])arr );
    }
}

Another possibility would be to take dimension 1 as the base case:

public static Object addArraysN( Object arrayN1, Object arrayN2 )
{
    ArrayList<Integer> dimensions = new ArrayList<Integer>();
    ArrayN.getDimensions( arrayN1, dimensions );
    int[] dims = new int[dimensions.size()];
    for ( int i = 0; i < dims.length; i++ )
    {
        dims[i] = dimensions.get( i );
    }
    if ( dims.length == 1 )
    {
        Object arrayN3 = Array.newInstance( int.class, dims );
        for ( int i = 0; i < Array.getLength( arrayN1 ); i++ )
        {
            int sum = ((int[])arrayN1)[i] + ((int[])arrayN2)[i];
            Array.set( arrayN3, i, sum );
        }
        return arrayN3;
    }
    else
    {
        Object arrayN3 = Array.newInstance( int.class, dims );
        for ( int i = 0; i < Array.getLength( arrayN1 ); i++ )
        {
            Array.set( arrayN3, i, (int[])ArrayN.addArraysN( Array.get( arrayN1, i ), Array.get( arrayN2, i ) ) );
        }

        return arrayN3;
    }
}

Related questions

How to sum arrays in Java
Is it possible to dynamically build a multi-dimensional array in Java?
Iterating over arrays by reflection
Java Reflection - Get size of array object
Creating an n-dimension Array in Java during runtime
Initialising a multidimensional array in Java
finding sum of two dimensional array java
Adding matrices Java
Java Matrices Arrays

like image 356
John Avatar asked Nov 16 '13 16:11

John


2 Answers

Here is complete and simple solution. You can pass any dimension arrays to copyArray method.

package com.azry.test;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

public class MultiDimArray {

    public Object copyArray(Object srcArray1, Object srcArray2) {

        ArrayList<Integer> dimensions = new ArrayList<Integer>();
        getDimensions(srcArray1, dimensions);
        int[] dims = new int[dimensions.size()];
        for (int i = 0; i < dims.length; i++) {
            dims[i] = dimensions.get(i);
        }

        Object dstArray = Array.newInstance(int.class, dims);
        copyArray(srcArray1, srcArray2, dstArray);
        return dstArray;
    }

    public void copyArray(Object srcArray1, Object srcArray2, Object dstArray) {
        if (srcArray1 != null && srcArray1.getClass().isArray()) {
            if (srcArray1 instanceof int[]) {
                int[] s1 = (int[])srcArray1;
                int[] s2 = (int[])srcArray2;
                int[] d = (int[])dstArray;
                for (int i = 0; i < s1.length; i++) {
                    d[i] = s1[i] + s2[i];
                }
            }
            for (int i = 0; i < Array.getLength(srcArray1); i++) {
                copyArray(Array.get(srcArray1, i), Array.get(srcArray2, i), Array.get(dstArray, i));
            }
        }
    }

    public void getDimensions(Object array, List<Integer> dimensions) {
        if (array != null && array.getClass().isArray()) {
            dimensions.add(Array.getLength(array));
            if (Array.getLength(array) > 0) {
                getDimensions(Array.get(array, 0), dimensions);
            }
        }
    }

    public static void main(String[] args) {

        int[][][] srcArray1 = new int[2][3][4];
        for (int i = 0; i < srcArray1.length; i++) {
            for (int j = 0; j < srcArray1[i].length; j++) {
                for (int k = 0; k < srcArray1[i][j].length; k++) {
                    srcArray1[i][j][k] = 2;
                }
            }
        }

        int[][][] srcArray2 = new int[2][3][4];
        for (int i = 0; i < srcArray2.length; i++) {
            for (int j = 0; j < srcArray2[i].length; j++) {
                for (int k = 0; k < srcArray2[i][j].length; k++) {
                    srcArray2[i][j][k] = 3;
                }
            }
        }

        int[][][] dstArray = (int[][][])new MultiDimArray().copyArray(srcArray1, srcArray2);

        for (int i = 0; i < dstArray.length; i++) {
            for (int j = 0; j < dstArray[i].length; j++) {
                for (int k = 0; k < dstArray[i][j].length; k++) {
                    System.out.println("[" + i + "," + j + "," + k + "] = " + dstArray[i][j][k]);
                }
            }
        }
    }
}
like image 103
Nikoloz Avatar answered Oct 02 '22 04:10

Nikoloz


The problem is that you cannot treat arrays like you are currently doing: You receive Object vectorN1 in addVectorsN(...) that is actually (Object)matrice1, so int[][]. But then, you access it like (int)vectorN1, which is wrong, because it's actually an array, not an int. So, you should access to vectorN1 like this: int i = ...; vectorN1[i]; and I would then keep vectorN1 as int[][] instead of converting it into an Object. And I would do the same for vectorN2 as well.

EDIT:

I would change

addVectorsN( (Object)matrice1, (Object)matrice2, 2, 5 ) ) to be

addVectorsN( matrice1, matrice2, 2, 5 ) )

and you are accessing it like (int)vectorN1 in

public static Object addVectorsN( Object vectorN1, Object vectorN2, 
    int dimension, int innerlength )
{
    if ( dimension == 0 )
    {
        return (int)vectorN1 + (int)vectorN2; (...) 

which I would change to be:

public static Object addVectorsN(int[][] vectorN1, int[][] vectorN2, 
    int dimension, int innerlength )

EDIT2:

and maybe you need something like this:

    if (vectorN1.length == 1 && vectorN2.length == 1)
    {
        if (vectorN1[0].length == 1  && vectorN2[0].length == 1)
        {
            return vectorN1[0][0] + vectorN2[0][0];
        }
    }
like image 36
Lucia Pasarin Avatar answered Oct 02 '22 03:10

Lucia Pasarin