在运行时设置数组的等级

时间:2021-01-23 21:38:15

I was wondering what the simplest way would be to implement an array who's rank is specified at runtime.

我想知道最简单的方法是实现一个在运行时指定排名的数组。

The example I am working on stores a array of boolean values for lattice points, and I want the user to be able to chose how many spatial dimensions the model uses at runtime.

我正在处理的示例存储了格点的布尔值数组,我希望用户能够选择模型在运行时使用的空间维数。

I've looked at the Array.newInstance() method:

我查看了Array.newInstance()方法:

dimensionOfSpace = userInputValue;  // this value comes from GUI or whatever
int latticeLength = 5;  // square lattice for simplicity

int[] dimensions = new int[dimensionOfSpace];
for(int i = 0; i < l.length; i++) l[i] = length; 
Object lattice = Array.newInstance(boolean.class, dimensions);

But accessing these values in any sort of way seems to require horribly slow methods such as recursively using Array.get until the returned value is no longer an array, i.e. using isArray().

但是以任何方式访问这些值似乎都需要非常慢的方法,例如递归使用Array.get,直到返回的值不再是数组,即使用isArray()。

Am I missing an obvious solution here? I would love to be able to access the values in a way similar to foo[i][j][k].

我在这里错过了一个明显的解决方案我希望能够以类似于foo [i] [j] [k]的方式访问这些值。

4 个解决方案

#1


5  

Looks like what you are looking for is for some way to declare how many dimensions an array has at runtime. I don't know how this could be done using a multidimensional ArrayList, or any multidimensional structure where you have to specify the dimensionality at compile time.

看起来你正在寻找的是某种方式来声明一个数组在运行时有多少维度。我不知道如何使用多维ArrayList或任何多维结构来完成此操作,您必须在编译时指定维度。

The only answer I see is to use a simple linear array wrapped in a class that converts multidimensional coordinate to and from the its position in the underlying array. This is basically how languages such as C stores multidimensional arrays by using one contiguous chunk of memory.

我看到的唯一答案是使用一个包含在类中的简单线性数组,该数组将多维坐标转换为其在底层数组中的位置。这基本上是C语言如何通过使用一个连续的内存块来存储多维数组。

The code would look something like this:

代码看起来像这样:

import java.util.*;

class MultiArray<T>{
    private int[] dimensions;
    private Object[] array;

    public MultiArray(int ... dimensions){
        this.dimensions=dimensions;
        //Utils.product returns the product of the ints in an array
        array=new Object[Utils.product(dimensions)];
    }

    public void set(T value, int ... coords){
        int pos=computePos(coords); 
        array[pos]=value;
    }

    public T get(int ... coords){
        int pos=computePos(coords);
        return (T)(array[pos]);
    }

    private int computePos(int[] coords){
        int pos=0;
        int factor=1;
        for (int i=0;i<coords.length;i++){
            pos+=factor*coords[i];
            factor*=dimensions[i];
        }
        return pos;
    }
}

class Main{
    public static void main(String args[]){
        MultiArray<Integer> m=new MultiArray<Integer>(new int[]{5,4,3}); 
        Random r=new Random();

        for(int i=0;i<5;i++)
            for(int j=0;j<4;j++)
                for(int k=0;k<3;k++)
                    m.set(r.nextInt(),i,j,k);
        for(int i=0;i<5;i++){
            for(int j=0;j<4;j++){
                for(int k=0;k<3;k++)
                    System.out.print(m.get(i,j,k)+" ");     
                System.out.println("");
            }
            System.out.println("\n");
        }
    }
}

class Utils{
    public static int product(int...a){
        int ret=1;
        for (int x:a) ret*=x;
        return ret;
    } 
}

#2


3  

Checkout Java Collections. It contains a class called ArrayList that grows in size as needed.

Checkout Java Collections。它包含一个名为ArrayList的类,它根据需要增大。

One dimensional

List<Boolean> a = new ArrayList<Boolean>();

List a = new ArrayList ();

Two Dimensional

List<List<Boolean>> b = new List<List<Boolean>>();

List > b = new List >();

Three Dimensional

List<List<List<Boolean>>> c = new List<List<List<Boolean>>>();

List >> c = new List >>();

And you'd access the item as c.get(i).get(j).get(k) instead of c[i][j][k] as in a 3d array. Or even better, wrap it in your own Class, and use a get() method there. So it becomes:

并且您将以c.get(i).get(j).get(k)而不是c [i] [j] [k]的形式访问该项目,如同在3d数组中一样。或者甚至更好,将它包装在您自己的类中,并在那里使用get()方法。所以它变成了:

c.get(i, j, k);

c.get(i,j,k);

Edit:

To have a multi-dimensional list of depth N, remove the Boolean type indictor and simply create lists as

要获得深度为N的多维列表,请删除布尔类型指示符,并将列表创建为

List level1 = new ArrayList();
List level2 = new ArrayList();
List level3 = new ArrayList();
level1.add(level2);
level2.add(level3);

and so on..

等等..

#3


3  

I'm going to use the term 'rank' to mean the 'number-of-dimensions' in your array. So a vector has rank 1, a matrix has rank 2 and so on. You've already accepted an answer that by your own admission is not quite what you want. Here's an alternative to settling for less:

我将使用术语“rank”来表示数组中的“维数”。因此,向量具有等级1,矩阵具有等级2,依此类推。你已经接受了一个答案,你自己承认并不是你想要的。这是另一种解决方案:

Recall that computer memory is essentially linear and that what a compiler does when it gives you arrays is actually take care of transforming an index expression into a linear address. This is simplest to think about if you assume that all arrays are in contiguous memory, not always true. Suppose that you make a declaration such as ARRAY_OF_TYPE[10][10][10], ie it has 1000 elements. Then the element at position [3][5][4] is (my arrays are indexed from 1 not 0 -- change the sums that follow if you want to) at location baseAddress+354*size_of_element_of_TYPE.

回想一下,计算机内存本质上是线性的,编译器在为数组提供数据时所做的事实上是将索引表达式转换为线性地址。如果您假设所有数组都在连续内存中,这是最简单的考虑,并非总是如此。假设你做了一个声明,如ARRAY_OF_TYPE [10] [10] [10],即它有1000个元素。然后,在位置baseAddress + 354 * size_of_element_of_TYPE处,位置[3] [5] [4]处的元素是(我的数组从1开始索引而不是0 - 根据需要更改后面的总和)。

I expect you know where I'm going on this by now ...

我希望你现在知道我要去哪里...

At run time your program prompts for a list of integers from the user. Each integer specifies the size of one of the dimensions of the array, the number of integers specifies the rank of the array. Your program does some multiplications and you allocate a vector of the right length. OK, you have to write the indexing and de-indexing functions, but these should be fairly straightforward.

在运行时,程序会提示用户输入整数列表。每个整数指定数组的一个维度的大小,整数的数量指定数组的等级。你的程序进行一些乘法,你分配一个正确长度的向量。好的,你必须编写索引和去索引函数,但这些应该相当简单。

et voila you have an array whose rank is established at run time.

et voila你有一个数组,其排名是在运行时建立的。

#4


1  

I did a quick google search for "java tensor" which came up with DJEP, could that be something which fits your bill?

我做了一个快速的谷歌搜索“Java张量”,它提出了DJEP,这可能适合你的账单吗?

#1


5  

Looks like what you are looking for is for some way to declare how many dimensions an array has at runtime. I don't know how this could be done using a multidimensional ArrayList, or any multidimensional structure where you have to specify the dimensionality at compile time.

看起来你正在寻找的是某种方式来声明一个数组在运行时有多少维度。我不知道如何使用多维ArrayList或任何多维结构来完成此操作,您必须在编译时指定维度。

The only answer I see is to use a simple linear array wrapped in a class that converts multidimensional coordinate to and from the its position in the underlying array. This is basically how languages such as C stores multidimensional arrays by using one contiguous chunk of memory.

我看到的唯一答案是使用一个包含在类中的简单线性数组,该数组将多维坐标转换为其在底层数组中的位置。这基本上是C语言如何通过使用一个连续的内存块来存储多维数组。

The code would look something like this:

代码看起来像这样:

import java.util.*;

class MultiArray<T>{
    private int[] dimensions;
    private Object[] array;

    public MultiArray(int ... dimensions){
        this.dimensions=dimensions;
        //Utils.product returns the product of the ints in an array
        array=new Object[Utils.product(dimensions)];
    }

    public void set(T value, int ... coords){
        int pos=computePos(coords); 
        array[pos]=value;
    }

    public T get(int ... coords){
        int pos=computePos(coords);
        return (T)(array[pos]);
    }

    private int computePos(int[] coords){
        int pos=0;
        int factor=1;
        for (int i=0;i<coords.length;i++){
            pos+=factor*coords[i];
            factor*=dimensions[i];
        }
        return pos;
    }
}

class Main{
    public static void main(String args[]){
        MultiArray<Integer> m=new MultiArray<Integer>(new int[]{5,4,3}); 
        Random r=new Random();

        for(int i=0;i<5;i++)
            for(int j=0;j<4;j++)
                for(int k=0;k<3;k++)
                    m.set(r.nextInt(),i,j,k);
        for(int i=0;i<5;i++){
            for(int j=0;j<4;j++){
                for(int k=0;k<3;k++)
                    System.out.print(m.get(i,j,k)+" ");     
                System.out.println("");
            }
            System.out.println("\n");
        }
    }
}

class Utils{
    public static int product(int...a){
        int ret=1;
        for (int x:a) ret*=x;
        return ret;
    } 
}

#2


3  

Checkout Java Collections. It contains a class called ArrayList that grows in size as needed.

Checkout Java Collections。它包含一个名为ArrayList的类,它根据需要增大。

One dimensional

List<Boolean> a = new ArrayList<Boolean>();

List a = new ArrayList ();

Two Dimensional

List<List<Boolean>> b = new List<List<Boolean>>();

List > b = new List >();

Three Dimensional

List<List<List<Boolean>>> c = new List<List<List<Boolean>>>();

List >> c = new List >>();

And you'd access the item as c.get(i).get(j).get(k) instead of c[i][j][k] as in a 3d array. Or even better, wrap it in your own Class, and use a get() method there. So it becomes:

并且您将以c.get(i).get(j).get(k)而不是c [i] [j] [k]的形式访问该项目,如同在3d数组中一样。或者甚至更好,将它包装在您自己的类中,并在那里使用get()方法。所以它变成了:

c.get(i, j, k);

c.get(i,j,k);

Edit:

To have a multi-dimensional list of depth N, remove the Boolean type indictor and simply create lists as

要获得深度为N的多维列表,请删除布尔类型指示符,并将列表创建为

List level1 = new ArrayList();
List level2 = new ArrayList();
List level3 = new ArrayList();
level1.add(level2);
level2.add(level3);

and so on..

等等..

#3


3  

I'm going to use the term 'rank' to mean the 'number-of-dimensions' in your array. So a vector has rank 1, a matrix has rank 2 and so on. You've already accepted an answer that by your own admission is not quite what you want. Here's an alternative to settling for less:

我将使用术语“rank”来表示数组中的“维数”。因此,向量具有等级1,矩阵具有等级2,依此类推。你已经接受了一个答案,你自己承认并不是你想要的。这是另一种解决方案:

Recall that computer memory is essentially linear and that what a compiler does when it gives you arrays is actually take care of transforming an index expression into a linear address. This is simplest to think about if you assume that all arrays are in contiguous memory, not always true. Suppose that you make a declaration such as ARRAY_OF_TYPE[10][10][10], ie it has 1000 elements. Then the element at position [3][5][4] is (my arrays are indexed from 1 not 0 -- change the sums that follow if you want to) at location baseAddress+354*size_of_element_of_TYPE.

回想一下,计算机内存本质上是线性的,编译器在为数组提供数据时所做的事实上是将索引表达式转换为线性地址。如果您假设所有数组都在连续内存中,这是最简单的考虑,并非总是如此。假设你做了一个声明,如ARRAY_OF_TYPE [10] [10] [10],即它有1000个元素。然后,在位置baseAddress + 354 * size_of_element_of_TYPE处,位置[3] [5] [4]处的元素是(我的数组从1开始索引而不是0 - 根据需要更改后面的总和)。

I expect you know where I'm going on this by now ...

我希望你现在知道我要去哪里...

At run time your program prompts for a list of integers from the user. Each integer specifies the size of one of the dimensions of the array, the number of integers specifies the rank of the array. Your program does some multiplications and you allocate a vector of the right length. OK, you have to write the indexing and de-indexing functions, but these should be fairly straightforward.

在运行时,程序会提示用户输入整数列表。每个整数指定数组的一个维度的大小,整数的数量指定数组的等级。你的程序进行一些乘法,你分配一个正确长度的向量。好的,你必须编写索引和去索引函数,但这些应该相当简单。

et voila you have an array whose rank is established at run time.

et voila你有一个数组,其排名是在运行时建立的。

#4


1  

I did a quick google search for "java tensor" which came up with DJEP, could that be something which fits your bill?

我做了一个快速的谷歌搜索“Java张量”,它提出了DJEP,这可能适合你的账单吗?