7

Is it possible in Java to find the number of dimensions of an array with an 'a priori' unknown number of dimensions? That is, if one doesn't know the number of dimensions of a multidimensional matrix, how could it be retrieved, if possible?

4
  • 1
    Do you mean how to tell an int[] apart from an int[][][][][]? Commented Apr 22, 2014 at 21:56
  • 2
    How are you receiving this array, if you don't know its type? Simply as Object? Commented Apr 22, 2014 at 22:07
  • Right! You could receive it as an Object or as some variable user input. The case is, the true number of dimensions is unknown. (Don't confuse it with the number of elements in any row, column, or more complex geometries/structures). My interest is in determining the number of diferent dimensions in a matrix/hypermatrix. Commented Apr 23, 2014 at 0:56
  • To clarify: the number of dimensions is unknown for us, but obviously, it has to be known in some other environment or context (user point of view, for example). The important point is, we receive it with no knowledge of its number of dimensions, even they could be unknown until runtime. How to determine it? Thanks! Commented Apr 23, 2014 at 1:04

5 Answers 5

10

Does anyone know if it is possible in Java to get the number of dimensions of an array with an 'a priori' unknown number of dimensions? That is, if one doesn't know the number of dimensions of a multidimensional matrix, how could it be retrieved, if possible?

I'm not quiet sure if I understood correctly what you are trying to accomplish. If you just want to know how many elements are there in array, Anubian's answer is correct. But what I understood is that you want to calculate number of dimensions of a given general array.

public class Test {
    public static int getNumberOfDimensions(Class<?> type) {
        if (type.getComponentType() == null) {
            return 0;
        } else {
            return getNumberOfDimensions(type.getComponentType()) + 1;
        }
    }

    public static void main(String[] args) {
        System.out.println(getNumberOfDimensions(int[][][].class)   == 3);
        System.out.println(getNumberOfDimensions(int[][].class)     == 2);
        System.out.println(getNumberOfDimensions(int[][][][].class) == 4);
        System.out.println(getNumberOfDimensions(int.class)         == 0);
    }
}

If that's not what are you looking for, I'd have a hint: there is a difference between a length and dimension.


Update: I think this is completely irrelevant to what we were asked, but Nicola asked me in the comments:

This works perfectly, but what about if the number of dimensions is defined at run-time (for instance the user has to input the desired amount of dimensions)? How you could define and initialize the array?

The solution lies in some light reflection-based hacking:

import java.lang.reflect.Array;

public class Test {
    public static Class<?> getArrayType(Class<?> componentType, int dimensions) throws ClassNotFoundException {
        if (dimensions == 0) {
            return componentType;
        }

        String rawName = componentType.getName();
        switch (rawName) {
            case "byte":    rawName = "B"; break;
            case "char":    rawName = "C"; break;
            case "double":  rawName = "D"; break;
            case "float":   rawName = "F"; break;
            case "int":     rawName = "I"; break;
            case "long":    rawName = "J"; break;
            case "short":   rawName = "S"; break;
            case "boolean": rawName = "Z"; break;
            default:
                rawName = "L" + rawName + ";";
                break;
        }

        for (int i = 0; i < dimensions; i++) {
            rawName = "[" + rawName;
        }

        return Class.forName(rawName);
    }

    public static Object createArray(Class<?> componentType, int dimensions, int length) throws NegativeArraySizeException, ClassNotFoundException {
        if (dimensions == 0) {
            return null;
        }

        Object array = Array.newInstance(getArrayType(componentType, dimensions - 1), length);

        for (int i = 0; i < length; i++) {
            Array.set(array, i, createArray(componentType, dimensions - 1, length));
        }

        return array;
    }

    public static void main(String[] args) throws ClassNotFoundException {
        Object object = createArray(Integer.class, 3, 10);
        System.out.println(object.getClass());
    }
}

The trick is to construct a Class for N-dimensional array using a given component type. We can do that if we know how class names are stored on the lowest level. Rest of the code is just a simple not-interesting recursion.

Sign up to request clarification or add additional context in comments.

5 Comments

This works perfectly, but what about if the number of dimensions is defined at run-time (for instance the user has to input the desired amount of dimensions)? How you could define and initialize the array?
I don't think this is what we were asked, but it'd be possible using reflection.
@Nicola I updated my answer to include your question.
Ok, good point to use reflection to solve this issue. I'm not experienced in this field, but maybe reflection is not the most efficient way, but anyway from a theoretical and conceptual point of view it works. A possible improvement is to make the length parameter an array itself: with some little adaptation one could have the feature to define different size for each dimension.
Yes, of course, but I guess it's something everyone would be able to change. BTW: I don't think there's an real use-case for arrays with unknown number of dimensions. I don't remember if I have ever used a three-dimensional array, now we are talking about N-dimensional array... It's whole a theoretical task with no real usage. But since it was asked, I answered. It's always fun to hack up some solution like this!
1

Assuming your matrix is called m:

You can get the number of columns by running

m.length;

With Java, multidimensional arrays are actually arrays of arrays. The number of rows is variable. Assuming i is an integer between 0 and m.length-1 you can do:

m[i].length;

To get the number of elements in the row.

1 Comment

You're right, but you can not proceed with this approach indefinitely: suppose that you have a third or a fourth dimension... or even more complicated suppose you do not know how many are actually the dimensions (as stated in the question): an approach of this kind, 'hard-coded', in my opinion is not feasible
1

The initial problem here is that you can't begin by saying something to the effect of:

int getNumDimensions(int[] array) { ... }

Because this would fail if theArray was actually an int[][], int[][][], etc. But all arrays in Java are Object subclasses, so this can work for any number of dimensions:

int getNumDimensions(Object array) {zz
    if (array instanceof Object[]) {
        // array has at least 2 dimensions (e.g. int[][])
        return getNumDimensions(((Object[]) array)[0]) + 1;
    }
    if (array.getClass().isArray()) {
        // array is, by process of elimination, one-dimensional
        return 1;
    }
    return 0;
}

Edit: I've tried my hand at a non-recursive solution for those crazy million-dimensional arrays!

int getNumDimensions(Object array) {
    Object tmp = array;
    int nDimensions = 0;
    while (True) {
        if (array instanceof Object[]) {
            // tmp has at least 2 dimensions (e.g. int[][])
            tmp = ((Object[]) array)[0];
        }
        else if (tmp.getClass().isArray()) {
            // tmp is, by process of elimination, one-dimensional
            return nDimensions + 1;
        }
        nDimensions++;
    }
}

4 Comments

I don't have the JDK available at the moment, so please let me know if this code fails.
There are some compile and logic errors in the code. I've edited to correct these.
I've also pointed out in the edited code, if any dimension is size 0, there is no way to continue to count any dimensions after that one. In fact, if the array was allocated via the multianewarray, any further dimensions are not even allocated. According to JVM Spec, If any count value is zero, no subsequent dimensions are allocated.
Also worth noting, since the implementation only checks index 0, the result for jagged arrays may be different than expected. Consider new Object[]{new int[2], new int[3][1][2]}. The result will be 2 but if the implementation had checked index 1 from the Object[], it would have computed 4. But perhaps in that case, asking for the number of dimensions doesn't even make sense!
0

What I can suggest you is to manage this issue by using an array with only one dimension. Suppose to have N dimensions of sizes:

size of the N dimensions

Then you can define the size of your array as:

   int size = S_0*S_1*...*S_N-1;

Then you will initialize it, for instance for an array of integers:

int[] array = new int[size];

Then to refer to an item of the array (to read or write it), you have N indexes (because of N dimensions):

indexes to refer the array

What you need now is a way to transform this N indexes, in one single value that can be used as an index in the one-dimensional array, the generic formula is:

how transform the N indexes in one index for the one-dimensional array

Basically this formula 'skips' the correct number of previous dimensions and points to the right location. This formula can be simply implemented in methods like

int read(int[] array, int[] indexes);
void write(int[] array, int[] indexes, int values);

in order to keep the code readable. You may also implement this technique using a generic type, so the methods might work for any type.

2 Comments

A viable alternative, although it's not usable for determining what the asker's looking for.
I see what you mean, by my point is: how can you ever end up in a situation such as that described in the question, where you obtain an array (for example as a return value from a method, or a method parameter), without defining in the code the number of dimensions? I do not see how you could have a situation like that (in C would be different, by using a pointer int* array, which can point to an array of any dimension, but here we are in Java), so probably the asker himself had to implement a way to handle this problem.
0

Just look at its dynamic type either by looking directly in your code where it is initialized or by calling its class and examining its reflected attributes.

2 Comments

Can this be extended to find get the number of dimensions as an int?
a.getClass() will return the number of dimensions as the name of the class e.g. an int[][] would return a name of "class [[I". If you need this dynamically however, then you should look at the component type as Tomas has showed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.