如何在java中创建任意深度的嵌套数组?

时间:2022-11-17 21:19:30

I am trying to create an array of arrays of arrays etc..., except I don't know how many nested levels deep it needs to be until runtime.

我正在尝试创建一个数组数组等数组...,除了我不知道它需要多少嵌套级别,直到运行时。

Depending on the input, I might need either int[], int[][], int[][][][][][], or anything else. (For context, I am trying to construct an N-dimensional grid for a cellular automaton, where N is passed as a parameter.)

根据输入,我可能需要int [],int [] [],int [] [] [] [] [] []或其他任何东西。 (对于上下文,我正在尝试为元胞自动机构建一个N维网格,其中N作为参数传递。)

I don't have any code for you because I have no idea how to go about this; I suspect is not possible at all using just arrays. Any help, or alternative solutions, would be appreciated.

我没有任何代码,因为我不知道如何去做;我怀疑只使用数组是不可能的。任何帮助或替代解决方案,将不胜感激。

7 个解决方案

#1


9  

You could do this with an Object[], limiting its members to either Object[] or int[].

您可以使用Object []执行此操作,将其成员限制为Object []或int []。

For example, here's an array that goes three levels deep in one part, and two levels deep in another:

例如,这是一个数组在一个部分中有三个深度,在另一个部分中有两个深度:

   Object[] myarray = new Object[] {
         new Object[] { new int[] { 1, 2 }, 
                        new int[] { 3, 4 }},
         new int[] { 5, 6 } 
    };

After you've created it, you may want to access members. In your case, you know the depth N up front, so you know at what depth to expect an Object[] and at what depth to expect an int[].

创建它之后,您可能想要访问成员。在您的情况下,您知道前面的深度N,因此您知道期望Object []的深度以及期望int []的深度。

However, if you didn't know the depth, you could use reflection to determine whether a member is another Object[] level or a leaf int[].

但是,如果您不知道深度,则可以使用反射来确定成员是另一个Object []级别还是叶子int []。

    if ( myarray[0] instanceof Object[] ) {
           System.out.println("This should print true.");
    }

EDIT:

Here's a sketch [untested so far, sorry] of a method that access a member of an array of known depth, given an array of indices. The m_root member can be an Object[] or an int[]. (You could relax this further to support scalars.)

这是一个草图[目前为止未经测试,对不起]一个方法,在给定索引数组的情况下访问已知深度数组的成员。 m_root成员可以是Object []或int []。 (您可以进一步放松以支持标量。)

   public class Grid {
        private int m_depth;
        private Object m_root;
        ...
        public int get( int ... indices ) {
            assert( indices.length == m_depth );
            Object level = m_root;
            for ( int i = 0; i + 1 < m_depth; ++i ) {
                level = ((Object[]) level)[ indices[i] ];
            }
            int[] row = (int[]) level;
            return row[ indices[m_depth - 1] ];
        }
   }

#2


1  

This should be achievable using Object[], since arrays are objects:

这应该可以使用Object []实现,因为数组是对象:

int[] arr = {1,2,3};
int[] arr2 = {1,2,3};
int[] arr3 = {1,2,3};
int[] arr4 = {1,2,3};
Object[] arr5 = {arr, arr2}; // basically an int[][]
Object[] arr6 = {arr3, arr4}; // basically an int[][]
Object[] arr7 = {arr5, arr6}; // basically an int[][][]
// etc.

Note that one array doesn't have to contain arrays of the same dimensions:

请注意,一个数组不必包含相同维度的数组:

Object[] arr7 = {arr5, arr};

To prevent this (and to allow for easier access to the data), I suggest writing a class which has an Object member (which will be your int[] or Object[]) and a depth variable and some nice functions to give you access to what you want.

为了防止这种情况(并允许更容易访问数据),我建议编写一个具有Object成员的类(它将是你的int []或Object [])和一个深度变量以及一些很好的函数来提供访问权限到你想要的。

ArrayLists will also work:

ArrayLists也可以工作:

ArrayList array = new ArrayList();
array.add(new ArrayList());
array.add(new ArrayList());
((ArrayList)array.get(0)).add(new ArrayList());
// etc.

#3


1  

As your N increases going with nested arrays becomes less and less advantageous, especially when you have a grid structure. Memory usage goes up exponentially in N with this approach and the code becomes complex.

随着嵌套数组的N增加越来越有利,特别是当你有网格结构时。使用这种方法,N的内存使用量呈指数增长,代码变得复杂。

If your grid is sparsely populated (a lot of cells with the same value) you can instead have a collection of Cell objects where each of these holds a coordinate vector and the integer value of the cell. Every cell that is not in the collection is assumed to have a default value, which is your most common value.

如果您的网格是稀疏填充的(很多具有相同值的单元格),您可以使用一组Cell对象,其中每个对象都包含坐标向量和单元格的整数值。假设不在集合中的每个单元格都具有默认值,这是您最常用的值。

For faster access you can use for example a k-d tree (https://en.wikipedia.org/wiki/K-d_tree) but that depends a bit on your actual use-case.

为了更快地访问,您可以使用例如k-d树(https://en.wikipedia.org/wiki/K-d_tree),但这取决于您的实际用例。

#4


1  

@Andy Thomas explains how to do this using Object[] for the higher levels of the multidimensional array. Unfortunately, this means that the types are not correct to allow indexing, or indeed to allow element access without typecasts.

@Andy Thomas解释了如何使用Object []来实现更高级别的多维数组。不幸的是,这意味着类型不正确以允许索引,或者实际上允许在没有类型转换的情况下访问元素。

You can't do this:

你不能这样做:

    Object[] array = ...
    int i = array[1][2][3][4];

To get types that allow you to do the above, you need to create an object whose real type is (for example) int[][][][].

要获取允许您执行上述操作的类型,您需要创建一个实际类型为(例如)int [] [] [] []的对象。

But the flipside is that it is not really practical to use that style of indexing for N dimensional arrays where N is a variable. You can't write Java source code to do that unless you place a bound on N (i.e. up to 5) and treat the different cases individually. That becomes unmanageable very quickly.

但另一方面是,对N维数组使用这种索引方式并不实际,其中N是一个变量。您不能编写Java源代码来执行此操作,除非您对N(即最多5)设置绑定并单独处理不同的情况。这很快变得无法管理。

#5


0  

You can use Java reflection as Arrays are objects.

您可以使用Java反射,因为数组是对象。

    public static void main(String[] args) throws InstantiationException,
        IllegalAccessException, ClassNotFoundException {
    Class<?> intClass = int.class;
    Class<?> oneDimensionalArrayClass = Class.forName("[I");

    Object oneDimensionalIntArray1 = Array.newInstance(intClass, 1);
    Array.set(oneDimensionalIntArray1, 0, 1);
    Object oneDimensionalIntArray2 = Array.newInstance(intClass, 1);
    Array.set(oneDimensionalIntArray2, 0, 2);
    Object oneDimensionalIntArray3 = Array.newInstance(intClass, 1);
    Array.set(oneDimensionalIntArray3, 0, 3);

    Object twoDimensionalIntArray = Array.newInstance(oneDimensionalArrayClass, 3);
    Array.set(twoDimensionalIntArray, 0, oneDimensionalIntArray1);
    Array.set(twoDimensionalIntArray, 1, oneDimensionalIntArray2);
    Array.set(twoDimensionalIntArray, 2, oneDimensionalIntArray1);

    System.out.println(Array.get(Array.get(twoDimensionalIntArray, 1), 0));

}

The class Array with its static methods gives access on items while you can specify the dimension of your arrays with the number of leading "[".

具有静态方法的类Array提供对项的访问,同时您可以使用前导“[”的数量指定数组的维度。

#6


0  

The whole construct of multi-dimensional arrays is just the compiler doing some work for you on a big block of memory (ok as some have commented in java this is multiple blocks of memory). One way to deal with the problem you face is to use nested arraylists at runtime. Another (more performant) way is to just allocate a single-dimensional array of the size you need and do the indexing yourself. You could then hide the indexing code in a method that was passed all the details like an array de-reference.

多维数组的整个构造只是编译器在一大块内存上为你做了一些工作(好吧,因为有人在java中注释这是多块内存)。处理您遇到的问题的一种方法是在运行时使用嵌套的arraylists。另一种(更高性能)的方法是只分配您需要的大小的一维数组并自己进行索引。然后,您可以在传递所有详细信息(如数组取消引用)的方法中隐藏索引代码。

private int[] doAllocate(int[] dimensions)
{
    int totalElements = dimensions[0];

    for (int i=1; i< dimensions.length; i++)
    {
        totalElements *= dimensions[i];
    }

    int bigOne = new int[totalElements];

    return bigOne;
}

private int deReference(int[] dimensions, int[] indicies, int[] bigOne)
{
    int index = 0;

    // Not sure if this is only valid when the dimensions are all the same.
    for (int i=0; i<dimensions.length; i++)
    {
        index += Math.pow(dimensions[i],i) * indicies[dimensions.length - (i + 1)];
    }

    return bigOne[index];
}

#7


0  

Fields like you wrote above a checked and created by the compiler. If you want a dynamic data structure during runtime you could create your own data structure. Search for Composite Pattern. A small snippet should show you how it works:

上面写的字段是由编译器检查并创建的。如果您想在运行时期间使用动态数据结构,则可以创建自己的数据结构。搜索复合图案。一个小片段应该告诉你它是如何工作的:

interface IGrid {
  void insert(IGrid subgrid);
  void insert(int[] values);
}
class Grid implements IGrid {
  private IGrid subgrid;
  void insert(IGrid subgrid) {this.subgrid = subgrid;}
  void insert(int[] values) {/* Do nothing */}
}
class SubGrid implements IGrid {
  private int[] values;
  void insert(IGrid subgrid) {/* Do nothing */}
  void insert(int[] values) {this.values = values;}
}

You could simply create a Subgrid for int[] or a Grid with a Subgrid for int[][]. It's only a rudimental solution, you would have to create some code for working on your automaton's levels and values. I would do it this way. Hope it will help :) And look forward for more solutions^^

你可以简单地为int []创建一个Subgrid,或者为int [] []创建一个带子网格的Grid。这只是一个基本的解决方案,你必须创建一些代码来处理你的自动机的级别和值。我会这样做。希望它会有所帮助:)并期待更多的解决方案^^

#1


9  

You could do this with an Object[], limiting its members to either Object[] or int[].

您可以使用Object []执行此操作,将其成员限制为Object []或int []。

For example, here's an array that goes three levels deep in one part, and two levels deep in another:

例如,这是一个数组在一个部分中有三个深度,在另一个部分中有两个深度:

   Object[] myarray = new Object[] {
         new Object[] { new int[] { 1, 2 }, 
                        new int[] { 3, 4 }},
         new int[] { 5, 6 } 
    };

After you've created it, you may want to access members. In your case, you know the depth N up front, so you know at what depth to expect an Object[] and at what depth to expect an int[].

创建它之后,您可能想要访问成员。在您的情况下,您知道前面的深度N,因此您知道期望Object []的深度以及期望int []的深度。

However, if you didn't know the depth, you could use reflection to determine whether a member is another Object[] level or a leaf int[].

但是,如果您不知道深度,则可以使用反射来确定成员是另一个Object []级别还是叶子int []。

    if ( myarray[0] instanceof Object[] ) {
           System.out.println("This should print true.");
    }

EDIT:

Here's a sketch [untested so far, sorry] of a method that access a member of an array of known depth, given an array of indices. The m_root member can be an Object[] or an int[]. (You could relax this further to support scalars.)

这是一个草图[目前为止未经测试,对不起]一个方法,在给定索引数组的情况下访问已知深度数组的成员。 m_root成员可以是Object []或int []。 (您可以进一步放松以支持标量。)

   public class Grid {
        private int m_depth;
        private Object m_root;
        ...
        public int get( int ... indices ) {
            assert( indices.length == m_depth );
            Object level = m_root;
            for ( int i = 0; i + 1 < m_depth; ++i ) {
                level = ((Object[]) level)[ indices[i] ];
            }
            int[] row = (int[]) level;
            return row[ indices[m_depth - 1] ];
        }
   }

#2


1  

This should be achievable using Object[], since arrays are objects:

这应该可以使用Object []实现,因为数组是对象:

int[] arr = {1,2,3};
int[] arr2 = {1,2,3};
int[] arr3 = {1,2,3};
int[] arr4 = {1,2,3};
Object[] arr5 = {arr, arr2}; // basically an int[][]
Object[] arr6 = {arr3, arr4}; // basically an int[][]
Object[] arr7 = {arr5, arr6}; // basically an int[][][]
// etc.

Note that one array doesn't have to contain arrays of the same dimensions:

请注意,一个数组不必包含相同维度的数组:

Object[] arr7 = {arr5, arr};

To prevent this (and to allow for easier access to the data), I suggest writing a class which has an Object member (which will be your int[] or Object[]) and a depth variable and some nice functions to give you access to what you want.

为了防止这种情况(并允许更容易访问数据),我建议编写一个具有Object成员的类(它将是你的int []或Object [])和一个深度变量以及一些很好的函数来提供访问权限到你想要的。

ArrayLists will also work:

ArrayLists也可以工作:

ArrayList array = new ArrayList();
array.add(new ArrayList());
array.add(new ArrayList());
((ArrayList)array.get(0)).add(new ArrayList());
// etc.

#3


1  

As your N increases going with nested arrays becomes less and less advantageous, especially when you have a grid structure. Memory usage goes up exponentially in N with this approach and the code becomes complex.

随着嵌套数组的N增加越来越有利,特别是当你有网格结构时。使用这种方法,N的内存使用量呈指数增长,代码变得复杂。

If your grid is sparsely populated (a lot of cells with the same value) you can instead have a collection of Cell objects where each of these holds a coordinate vector and the integer value of the cell. Every cell that is not in the collection is assumed to have a default value, which is your most common value.

如果您的网格是稀疏填充的(很多具有相同值的单元格),您可以使用一组Cell对象,其中每个对象都包含坐标向量和单元格的整数值。假设不在集合中的每个单元格都具有默认值,这是您最常用的值。

For faster access you can use for example a k-d tree (https://en.wikipedia.org/wiki/K-d_tree) but that depends a bit on your actual use-case.

为了更快地访问,您可以使用例如k-d树(https://en.wikipedia.org/wiki/K-d_tree),但这取决于您的实际用例。

#4


1  

@Andy Thomas explains how to do this using Object[] for the higher levels of the multidimensional array. Unfortunately, this means that the types are not correct to allow indexing, or indeed to allow element access without typecasts.

@Andy Thomas解释了如何使用Object []来实现更高级别的多维数组。不幸的是,这意味着类型不正确以允许索引,或者实际上允许在没有类型转换的情况下访问元素。

You can't do this:

你不能这样做:

    Object[] array = ...
    int i = array[1][2][3][4];

To get types that allow you to do the above, you need to create an object whose real type is (for example) int[][][][].

要获取允许您执行上述操作的类型,您需要创建一个实际类型为(例如)int [] [] [] []的对象。

But the flipside is that it is not really practical to use that style of indexing for N dimensional arrays where N is a variable. You can't write Java source code to do that unless you place a bound on N (i.e. up to 5) and treat the different cases individually. That becomes unmanageable very quickly.

但另一方面是,对N维数组使用这种索引方式并不实际,其中N是一个变量。您不能编写Java源代码来执行此操作,除非您对N(即最多5)设置绑定并单独处理不同的情况。这很快变得无法管理。

#5


0  

You can use Java reflection as Arrays are objects.

您可以使用Java反射,因为数组是对象。

    public static void main(String[] args) throws InstantiationException,
        IllegalAccessException, ClassNotFoundException {
    Class<?> intClass = int.class;
    Class<?> oneDimensionalArrayClass = Class.forName("[I");

    Object oneDimensionalIntArray1 = Array.newInstance(intClass, 1);
    Array.set(oneDimensionalIntArray1, 0, 1);
    Object oneDimensionalIntArray2 = Array.newInstance(intClass, 1);
    Array.set(oneDimensionalIntArray2, 0, 2);
    Object oneDimensionalIntArray3 = Array.newInstance(intClass, 1);
    Array.set(oneDimensionalIntArray3, 0, 3);

    Object twoDimensionalIntArray = Array.newInstance(oneDimensionalArrayClass, 3);
    Array.set(twoDimensionalIntArray, 0, oneDimensionalIntArray1);
    Array.set(twoDimensionalIntArray, 1, oneDimensionalIntArray2);
    Array.set(twoDimensionalIntArray, 2, oneDimensionalIntArray1);

    System.out.println(Array.get(Array.get(twoDimensionalIntArray, 1), 0));

}

The class Array with its static methods gives access on items while you can specify the dimension of your arrays with the number of leading "[".

具有静态方法的类Array提供对项的访问,同时您可以使用前导“[”的数量指定数组的维度。

#6


0  

The whole construct of multi-dimensional arrays is just the compiler doing some work for you on a big block of memory (ok as some have commented in java this is multiple blocks of memory). One way to deal with the problem you face is to use nested arraylists at runtime. Another (more performant) way is to just allocate a single-dimensional array of the size you need and do the indexing yourself. You could then hide the indexing code in a method that was passed all the details like an array de-reference.

多维数组的整个构造只是编译器在一大块内存上为你做了一些工作(好吧,因为有人在java中注释这是多块内存)。处理您遇到的问题的一种方法是在运行时使用嵌套的arraylists。另一种(更高性能)的方法是只分配您需要的大小的一维数组并自己进行索引。然后,您可以在传递所有详细信息(如数组取消引用)的方法中隐藏索引代码。

private int[] doAllocate(int[] dimensions)
{
    int totalElements = dimensions[0];

    for (int i=1; i< dimensions.length; i++)
    {
        totalElements *= dimensions[i];
    }

    int bigOne = new int[totalElements];

    return bigOne;
}

private int deReference(int[] dimensions, int[] indicies, int[] bigOne)
{
    int index = 0;

    // Not sure if this is only valid when the dimensions are all the same.
    for (int i=0; i<dimensions.length; i++)
    {
        index += Math.pow(dimensions[i],i) * indicies[dimensions.length - (i + 1)];
    }

    return bigOne[index];
}

#7


0  

Fields like you wrote above a checked and created by the compiler. If you want a dynamic data structure during runtime you could create your own data structure. Search for Composite Pattern. A small snippet should show you how it works:

上面写的字段是由编译器检查并创建的。如果您想在运行时期间使用动态数据结构,则可以创建自己的数据结构。搜索复合图案。一个小片段应该告诉你它是如何工作的:

interface IGrid {
  void insert(IGrid subgrid);
  void insert(int[] values);
}
class Grid implements IGrid {
  private IGrid subgrid;
  void insert(IGrid subgrid) {this.subgrid = subgrid;}
  void insert(int[] values) {/* Do nothing */}
}
class SubGrid implements IGrid {
  private int[] values;
  void insert(IGrid subgrid) {/* Do nothing */}
  void insert(int[] values) {this.values = values;}
}

You could simply create a Subgrid for int[] or a Grid with a Subgrid for int[][]. It's only a rudimental solution, you would have to create some code for working on your automaton's levels and values. I would do it this way. Hope it will help :) And look forward for more solutions^^

你可以简单地为int []创建一个Subgrid,或者为int [] []创建一个带子网格的Grid。这只是一个基本的解决方案,你必须创建一些代码来处理你的自动机的级别和值。我会这样做。希望它会有所帮助:)并期待更多的解决方案^^