6

Suppose we have multidimensional array, and the number of dimensions is known only at runtime. And suppose we have an integer number of indices.

How to apply indices to array so to access array's element?

UPDATE

Suppose:

int [] indices = new int { 2, 7, 3, ... , 4}; // indices of some element
int X = indices.length; // number of dimensions
Object array = .... // multidimensional array with number of dimensions X

...

I want to fetch the element addressed by indices indices from array.

UPDATE 2

I wrote following code based on recursion:

package tests;

import java.util.Arrays;

public class Try_Multidimensional {

    private static int element;

    public static int[] tail(int[] indices) {
        return Arrays.copyOfRange(indices, 1, indices.length);
    }


    public static Object[] createArray(int ... sizes) {

        Object[] ans = new Object[sizes[0]];

        if( sizes.length == 1 ) {
            for(int i=0; i<ans.length; ++i ) {
                ans[i] = element++;
            }
        }

        else {
            for(int i=0; i<ans.length; ++i) {
                ans[i] = createArray(tail(sizes)); 
            }
        }

        return ans;

    }

    public static Object accessElement(Object object, int ... indices) {

        if( object instanceof Object[] ) {

            Object[] array = (Object[]) object;

            return accessElement(array[indices[0]], tail(indices));

        }

        else {
            return object;
        }

    }

    public static void main(String[] args) {

        element = 0;
        Object array = createArray(4, 5, 12, 7);

        System.out.println(accessElement(array, 0, 0, 0, 0));
        System.out.println(accessElement(array, 0, 0, 0, 1));
        System.out.println(accessElement(array, 1, 0, 10, 0));
        try {
            System.out.println(accessElement(array, 0, 5, 0, 1));
        }
        catch(Exception e) {
            System.out.println(e.toString());
        }

    System.out.println(4*5*12*7-1);
    System.out.println(accessElement(array, 3, 4, 11, 6));

    }

}

The questions are:

1) are there any reliable ready-made methods from JDK and/or famous libraries for this?

2) I was using Object. can it be avoided? can I create/access variable dimensionality array of built-in or specific type? how large is a payoff due to using Object?

Suzan Cioc
  • 29,281
  • 63
  • 213
  • 385

4 Answers4

2
int index(Object arrayToIndex, int... indices) {
    for (int i = 0; i < indices.length - 1; i++) {
        arrayToIndex = ((Object[]) arrayToIndex)[indices[i]];
    }
    return ((int[]) arrayToIndex)[indices[indices.length-1]];
}

Loop through the dimensions and index each dimension, one at a time. The casts and the special case for the last dimension are going to be annoying, so I recommend wrapping this in some sort of n-dimensional array class. (It looks like some options already exist.)

Community
  • 1
  • 1
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • I think she wants to create an array with N dimensions where N isn't known until runtime, which the language does not support. – Jeff Scott Brown Jun 27 '14 at 09:37
  • @JeffScottBrown: The question just talks about accessing the array. Creating it is another matter. – user2357112 Jun 27 '14 at 09:38
  • I misunderstood the question in the same way you did. The question includes "Object array = .... // multidimensional array with number of dimensions X" and it is the right hand side there that is the thing that cannot be done. You can't create an array with a dynamic number of dimensions, which is what I think she is after. Maybe I am wrong about what she is after. – Jeff Scott Brown Jun 27 '14 at 09:40
  • The question has changed and appears to be asking something different. I am going to surrender. ;) Best of luck to the OP. – Jeff Scott Brown Jun 27 '14 at 09:41
  • Why can't you rewrite `for (int i = 0; i < indices.length - 1; i++)` -> `for (int i = 0; i < indices.length; i++)` and at the end just `return arrayToIndex;`? – Suzan Cioc Jun 27 '14 at 10:03
0

You can discover the size of each dimension as individual arrays (because that is what they are):

public void someMEthod(int[][][] matrix) {
    int d1 = matrix.length;
    int d2 = 0;
    int d3 = 0;
    if(d1 > 0) {
        d2 = matrix[0].length;
        if(d2 > 0) {
            d3 = matrix[0][0].length;
        }
    }
    System.out.println("Dimension 1 is " + d1);
    System.out.println("Dimension 2 is " + d2);
    System.out.println("Dimension 3 is " + d3);
}

I hope that helps.

Jeff Scott Brown
  • 26,804
  • 2
  • 30
  • 47
  • The number of dimensions is variable, not just the size of each dimension. – user2357112 Jun 27 '14 at 09:32
  • I guess the problem here is that the array has an unknown number of dimensions, so `matrix` cannot be arbitrarily declared as an `int[][][]`. – Xavi López Jun 27 '14 at 09:32
  • The original question has been edited such that I am not sure this really answers that question. The answer to the question as it is currently written is that you cannot do that. When the array is declared, the number of dimensions has to be known. The values of each of those dimensions can be runtime dynamic, but not the number of dimensions. – Jeff Scott Brown Jun 27 '14 at 09:33
  • You can do this with ArrayList by having an ArrayList of ArrayList of ArrayList and in that case the number of dimensions can be dynamic, but the question as written about arrays (not ArrayList) is such that you cannot do it. – Jeff Scott Brown Jun 27 '14 at 09:34
0

I found a kinda fun way to do it using reflection. This is just some code I threw together but you could wrap it in a class and make it all pretty.

// build and fill an array to the given depth
public static Object[] constructArray(Object[] array, int depth) {
    if(depth == 0)
        return null;

    for(int i=0;i<array.length;i++) {
        Array.set(array, i, constructArray(new Object[array.length], depth-1));
    }
    return array;
}

// sets a value in the multi dimensional array using the indicies
public static void setArrayUsingIndecies(Object array, int[] indicies, Object value) {
    if(indicies.length == 0)
        return;

    for(int i=0;i<indicies.length-1;i++) {
        array = Array.get(array, indicies[i]);
    }

    Array.set(array, indicies[indicies.length-1], value);
}

// gets a value in the multi dimmensional array using the indicies
public static Object getArrayUsingIndecies(Object array, int[] indicies) {

    Object value = array;
    for(int i=0;i<indicies.length;i++) {
        value = Array.get(value, indicies[i]);
    }

    return value;
}

Heres a bit of sample code

int numberOfDimmensions = 2;

Object array = constructArray(new Object[numberOfDimmensions], numberOfDimmensions);

int [] indices = new int [] { 0, 1 };
setArrayUsingIndecies(array, indices, "Hello");
System.out.println(getArrayUsingIndecies(array, indices)); // Hello
indices = new int [] { 0, 0 };
System.out.println(getArrayUsingIndecies(array, indices)); // null
ug_
  • 11,267
  • 2
  • 35
  • 52
0

Is it more simple than we think? How about this approach:

int [] indices = new int { 2, 7, 3, ... , 4}; // indices of some element
int X = indices.length; // number of dimensions
Object array = new Object[X].... // multidimensional array with number of dimensions X

and then:

Object myObject = array[indices[1]]  // myObject references the 7th element of array

You have to make sure though, that your indices array does not contain a number larger then the size of indices - 1. For example

indices = new int [5,4,3,2,1] // ok
indices = new int [6,4,3,2,1] // not ok, because you would access the 6th Element in an arry with length 5