9

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

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

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

4

7 回答 7

11

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

例如,这是一个数组,其中一个部分有三层,另一部分有两层:

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

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

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

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

编辑:

这是一个草图[到目前为止未经测试,抱歉],在给定索引数组的情况下,该方法访问已知深度数组的成员。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] ];
        }
   }
于 2013-07-04T23:35:46.297 回答
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};

为了防止这种情况(并允许更轻松地访问数据),我建议编写一个具有Object成员(将是您的int[]or Object[])和深度变量和一些不错的函数的类,以使您可以访问所需的内容。

ArrayLists 也可以:

ArrayList array = new ArrayList();
array.add(new ArrayList());
array.add(new ArrayList());
((ArrayList)array.get(0)).add(new ArrayList());
// etc.
于 2013-07-04T23:37:27.197 回答
1

随着 N 的增加,嵌套数组的优势越来越小,尤其是当您有网格结构时。使用这种方法,内存使用量在 N 中呈指数增长,并且代码变得复杂。

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

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

于 2013-07-05T00:03:50.307 回答
1

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

你不能这样做:

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

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

但另一方面是,对其中 N 是变量的 N 维数组使用这种索引方式并不实际。您不能编写 Java 源代码来执行此操作,除非您在 N 上设置一个界限(即最多 5 个)并分别处理不同的情况。这很快就会变得难以管理。

于 2013-07-05T00:55:17.577 回答
0

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

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];
}
于 2013-07-04T23:35:27.210 回答
0

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

}

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

于 2013-07-04T23:49:37.983 回答
0

像您在编译器检查和创建的上方编写的字段。如果您想要在运行时动态数据结构,您可以创建自己的数据结构。搜索Composite Pattern。一个小片段应该向您展示它是如何工作的:

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

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

于 2013-07-04T23:51:55.873 回答