Is it possible to dynamically build a multi-dimensional array in Java? Is it possible to dynamically build a multi-dimensional array in Java? arrays arrays

Is it possible to dynamically build a multi-dimensional array in Java?


It is actually possible to do in java. (I'm a bit surprised I must say.)

Disclaimer; I never ever want to see this code anywhere else than as an answer to this question. I strongly encourage you to use Lists.

import java.lang.reflect.Array;import java.util.*;public class Test {    public static int[] tail(int[] arr) {        return Arrays.copyOfRange(arr, 1, arr.length);    }    public static void setValue(Object array, String value, int... indecies) {        if (indecies.length == 1)            ((String[]) array)[indecies[0]] = value;        else            setValue(Array.get(array, indecies[0]), value, tail(indecies));    }    public static void fillWithSomeValues(Object array, String v, int... sizes) {        for (int i = 0; i < sizes[0]; i++)            if (sizes.length == 1)                ((String[]) array)[i] = v + i;            else                fillWithSomeValues(Array.get(array, i), v + i, tail(sizes));    }    public static void main(String[] args) {        // Randomly choose number of dimensions (1, 2 or 3) at runtime.        Random r = new Random();        int dims = 1 + r.nextInt(3);        // Randomly choose array lengths (1, 2 or 3) at runtime.        int[] sizes = new int[dims];        for (int i = 0; i < sizes.length; i++)            sizes[i] = 1 + r.nextInt(3);        // Create array        System.out.println("Creating array with dimensions / sizes: " +                Arrays.toString(sizes).replaceAll(", ", "]["));        Object multiDimArray = Array.newInstance(String.class, sizes);        // Fill with some         fillWithSomeValues(multiDimArray, "pos ", sizes);        System.out.println(Arrays.deepToString((Object[]) multiDimArray));    }}

Example Output:

Creating array with dimensions / sizes: [2][3][2][[[pos 000, pos 001], [pos 010, pos 011], [pos 020, pos 021]], [[pos 100, pos 101], [pos 110, pos 111], [pos 120, pos 121]]]


Arrays are type-safe in java - that applies to simple arrays and "multi-dimensional" arrays - i.e. arrays of arrays.

If the depth of nesting is variable at runtime, then the best you can do is to use an array that corresponds to the known minimum nesting depth (presumably 1.) The elements in this array with then either be simple elements, or if further nesting is required, another array. An Object[] array will allow you to do this, since nested arrays themselves are also considered Objects, and so fit within the type system.

If the nesting is completely regular, then you can preempt this regularity and create an appropriate multimensional array, using Array.newInstance(String.class, dimension1, dimension2, ...), If nesting is irregular, you will be better off using nested lists, which allow for a "jagged" structure and dynamic sizing. You can have a jagged structure, at the expence of generics. Generics cannot be used if the structure is jagged since some elements may be simple items while other elements may be further nested lists.


So you can pass multiple dimensions to Array.newInstance, but that forces a fixed length for each dimension. If that's OK, you can use this:

// We already know from scanning the input that we need a 2 x 4 array.// Obviously this array would be created some other way. Probably through// a List.toArray operation.final int[] dimensions = new int[2];dimensions[0] = 2;dimensions[1] = 4;// Create the array, giving the dimensions as the second input.Object array = Array.newInstance(String.class, dimensions);// At this point, array is a String[2][4].// It looks like this, when the first dimension is output:// [[Ljava.lang.String;@3e25a5, [Ljava.lang.String;@19821f]//// The second dimensions look like this:// [null, null, null, null]

The other option would be to build them up from the bottom, using getClass on the previous level of array as the input for the next level. The following code runs and produces a jagged array as defined by the nodes:

import java.lang.reflect.Array;public class DynamicArrayTest{    private static class Node    {        public java.util.List<Node> children = new java.util.LinkedList<Node>();        public int length = 0;    }    public static void main(String[] args)    {        Node node1 = new Node();        node1.length = 1;        Node node2 = new Node();        node2.length = 2;        Node node3 = new Node();        node3.length = 3;        Node node4 = new Node();        node4.children.add(node1);        node4.children.add(node2);        Node node5 = new Node();        node5.children.add(node3);        Node node6 = new Node();        node6.children.add(node4);        node6.children.add(node5);        Object array = createArray(String.class, node6);        outputArray(array); System.out.println();    }    private static Object createArray(Class<?> type, Node root)    {        if (root.length != 0)        {            return Array.newInstance(type, root.length);        }        else        {            java.util.List<Object> children = new java.util.ArrayList<Object>(root.children.size());            for(Node child : root.children)            {                children.add(createArray(type, child));            }            Object array = Array.newInstance(children.get(0).getClass(), children.size());            for(int i = 0; i < Array.getLength(array); ++i)            {                Array.set(array, i, children.get(i));            }            return array;        }    }    private static void outputArray(Object array)    {        System.out.print("[ ");        for(int i = 0; i < Array.getLength(array); ++i)        {            Object element = Array.get(array, i);            if (element != null && element.getClass().isArray())                outputArray(element);            else                System.out.print(element);            System.out.print(", ");        }        System.out.print("]");    }}