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

如何在java中创建任意深度的嵌套数组?,java,arrays,cellular-automata,Java,Arrays,Cellular Automata,我正在尝试创建一个数组数组,数组数组等等,只是在运行时之前我不知道需要多少嵌套层 根据输入的不同,我可能需要int[]、int[]、int[][]、int[][]或其他任何内容。在上下文中,我试图为细胞自动机构造一个N维网格,其中N作为一个参数传递 我没有任何代码给你,因为我不知道该怎么做;我怀疑仅仅使用数组是不可能的。任何帮助或替代解决方案都将不胜感激。多维数组的整个构造只是编译器在一大块内存上为您做一些工作,好的,正如一些人在java中评论的那样,这是多块内存。处理您面临的问题的一种方法是在

我正在尝试创建一个数组数组,数组数组等等,只是在运行时之前我不知道需要多少嵌套层

根据输入的不同,我可能需要int[]、int[]、int[][]、int[][]或其他任何内容。在上下文中,我试图为细胞自动机构造一个N维网格,其中N作为一个参数传递


我没有任何代码给你,因为我不知道该怎么做;我怀疑仅仅使用数组是不可能的。任何帮助或替代解决方案都将不胜感激。

多维数组的整个构造只是编译器在一大块内存上为您做一些工作,好的,正如一些人在java中评论的那样,这是多块内存。处理您面临的问题的一种方法是在运行时使用嵌套的ArrayList。另一种更有效的方法是只分配一个所需大小的一维数组,然后自己编制索引。然后,您可以将索引代码隐藏在一个方法中,该方法像数组反引用一样传递所有细节

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];
}

可以对对象[]执行此操作,将其成员限制为对象[]或int[]

例如,这里有一个数组,一个部分有三层深,另一个部分有两层深:

   Object[] myarray = new Object[] {
         new Object[] { new int[] { 1, 2 }, 
                        new int[] { 3, 4 }},
         new int[] { 5, 6 } 
    };
创建后,您可能希望访问成员。在您的例子中,您知道前面的深度N,因此您知道对象[]的深度以及int[]的深度

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

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

下面是一个方法的草图[到目前为止还没有测试过,很抱歉],该方法在给定索引数组的情况下访问已知深度数组的成员。m_根成员可以是对象[]或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] ];
        }
   }

这应该可以通过使用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.
请注意,一个数组不必包含相同维度的数组:

Object[] arr7 = {arr5, arr};
为了防止这种情况发生,并允许更容易地访问数据,我建议编写一个类,该类具有一个对象成员,即int[]或Object[],以及一个深度变量和一些漂亮的函数,以便访问所需的内容

ArrayList也可以工作:

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

可以使用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));

}

类数组及其静态方法提供对项的访问,而您可以使用前导数指定数组的维度[.

类似于您在上面编写的字段,由编译器检查并创建。如果您希望在运行时使用动态数据结构,则可以创建自己的数据结构。搜索复合模式。一个小片段应向您展示其工作原理:

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;}
}

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

随着N的增加,使用嵌套数组的优势越来越小,特别是在网格结构的情况下。内存使用率使用这种方法,s在N中呈指数上升,代码变得复杂

如果网格中稀疏地填充了许多具有相同值的单元格,则可以使用单元格对象集合,其中每个单元格对象都包含一个坐标向量和单元格的整数值。假定不在集合中的每个单元格都有一个默认值,这是最常见的值


为了更快地访问,您可以使用例如k-d树,但这取决于您的实际用例。

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

你不能这样做:

    Object[] array = ...
    int i = array[1][2][3][4];
要获取允许您执行上述操作的类型,您需要创建一个实际类型为int[]的对象


但另一方面,对于N是变量的N维数组,使用这种类型的索引是不实际的。除非在N上加上一个界,即最多5个,并分别处理不同的情况,否则无法编写Java源代码来实现这一点。这很快就会变得难以管理。

考虑只使用int[]然后简单地计算N=10的1,2,3是索引1*10*10+2*10+3=123?我怀疑仅仅使用数组是不可能的。这是正确的。你必须编写一个自己的类来模仿这种行为。我建议重新考虑你的数据结构,一个int[][]或者任何接近它行为的东西都会让你的大脑崩溃…@Thorbjørnravandersen:我已经考虑了第一个;这是我现在的主要选择。但是,可以支持的最大尺寸和尺寸都相当小。关于结石
由于索引解决方案太小,我的数学可能是错误的,但一个维数为max int的int数组占用了8gb的内存。。。您需要多大的阵列?如果绝对必要,我想象你可以有一个max int数组数组,然后如果计算的索引超过第一个数组的边界,那么溢出到第二个数组,依此类推。这在C中是正确的,但在Java中不是。Java的数组实际上是由嵌套引用构建的,类似于C中的双**2D数组表示法。你是对的,但从使用它的代码的角度来看,这并不重要,只要数组中的元素总数不超过2 Gig 32位的限制。对,你可以像Java中那样自己做,但是您的回答听起来像是Java编译器在幕后处理它们的方式。在C语言中,它们实际上区分了锯齿状的类Java数组和语法为true的数组。。。指数用户可以直接调用get1,2,3而不是getnew int[]{1,2,3}。只是小小的改进。