是否可以在 Java 中动态构建多维数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3104504/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to dynamically build a multi-dimensional array in Java?
提问by Jordan
Suppose we have the Java code:
假设我们有 Java 代码:
Object arr = Array.newInstance(Array.class, 5);
Would that run? As a further note, what if we were to try something like this:
那会跑吗?进一步说明,如果我们要尝试这样的事情会怎样:
Object arr1 = Array.newInstance(Array.class, 2);
Object arr2 = Array.newInstance(String.class, 4);
Object arr3 = Array.newInstance(String.class, 4);
Array.set(arr1, 0, arr2);
Array.set(arr1, 1, arr3);
Would arr1 then be a 2D array equivalent to:
那么 arr1 将是一个二维数组,相当于:
String[2][4] arr1;
How about this: what if we don't know the dimensions of this array until runtime?
怎么样:如果我们直到运行时才知道这个数组的维度怎么办?
Edit: if this helps (I'm sure it would...) we're trying to parse an array of unknown dimensions from a String of the form
编辑:如果这有帮助(我确定它会......)我们正在尝试从表单的字符串中解析未知维度的数组
[value1, value2, ...]
or
或者
[ [value11, value12, ...] [value21, value22, ...] ...]
And so on
等等
Edit2: In case someone as stupid as I am tries this junk, here's a version that at least compiles and runs. Whether or not the logic is sound is another question entirely...
Edit2:如果像我这样愚蠢的人尝试这个垃圾,这里有一个至少可以编译和运行的版本。逻辑是否合理完全是另一个问题......
Object arr1 = Array.newInstance(Object.class, x);
Object arr11 = Array.newInstance(Object.class, y);
Object arr12 = Array.newInstance(Object.class, y);
...
Object arr1x = Array.newInstance(Object.class, y);
Array.set(arr1, 0, arr11);
Array.set(arr1, 1, arr12);
...
Array.set(arr1, x-1, arr1x);
And so on. It just has to be a giant nested array of Objects
等等。它必须是一个巨大的嵌套对象数组
采纳答案by aioobe
It is actually possible to do in java. (I'm a bit surprised I must say.)
实际上可以用java来做。(我必须说,我有点惊讶。)
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.
免责声明;除了作为这个问题的答案之外,我从不想在其他任何地方看到这段代码。我强烈建议您使用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]]]
回答by mdma
Arrays are type-safe in java - that applies to simple arrays and "multi-dimensional" arrays - i.e. arrays of arrays.
数组在 java 中是类型安全的——适用于简单数组和“多维”数组——即数组的数组。
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.
如果嵌套深度在运行时是可变的,那么你能做的最好的事情就是使用一个对应于已知最小嵌套深度(大概是 1)的数组。然后这个数组中的元素要么是简单的元素,要么是进一步的嵌套是必需的,另一个数组。Object[] 数组将允许您执行此操作,因为嵌套数组本身也被视为对象,因此适合类型系统。
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.
如果嵌套是完全规则的,那么您可以抢占这种规则并创建一个适当的多维度数组,使用Array.newInstance(String.class, dimension1, dimension2, ...),如果嵌套是不规则的,则最好使用嵌套列表,它允许“锯齿状”结构和动态调整大小。你可以有一个锯齿状的结构,以泛型为代价。如果结构是锯齿状的,则不能使用泛型,因为某些元素可能是简单的项目,而其他元素可能是进一步嵌套的列表。
回答by jdmichal
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:
因此,您可以将多个维度传递给Array.newInstance,但这会强制每个维度的长度固定。如果没问题,你可以使用这个:
// 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 getClasson 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:
另一种选择是从底部构建它们,使用getClass数组的上一层作为下一层的输入。以下代码运行并生成节点定义的锯齿状数组:
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("]");
}
}
回答by jjnguy
Ok, if you are unsure of the dimensions of the array, then the following method won't work. However, if you do know the dimensions, do not use reflection. Do the following:
好的,如果您不确定数组的维度,那么以下方法将不起作用。但是,如果您知道尺寸,请不要使用反射。请执行下列操作:
You can dynamically build 2d arrays much easier than that.
您可以比这更容易地动态构建二维数组。
int x = //some value
int y = //some other value
String[][] arr = new String[x][y];
This will 'dynamically' create an xby y2d array.
这将“动态”创建一个x由y二维数组。
回答by aioobe
As a further note, what if we were to try something like this:
Object arr1 = Array.newInstance(Array.class, 2); Object arr2 = Array.newInstance(String.class, 4); Object arr3 = Array.newInstance(String.class, 4); Array.set(arr1, 0, arr2); ...
进一步说明,如果我们要尝试这样的事情会怎样:
Object arr1 = Array.newInstance(Array.class, 2); Object arr2 = Array.newInstance(String.class, 4); Object arr3 = Array.newInstance(String.class, 4); Array.set(arr1, 0, arr2); ...
No, you can't set an String[]value like that. You run into
不,您不能设置这样的String[]值。你遇到
Exception in thread "main" java.lang.IllegalArgumentException: array element type mismatch
at java.lang.reflect.Array.set(Native Method)
at Test.main(Test.java:12)
回答by OscarRyz
Effective Java item # (I don't remember) : Know and use the libraries.
Effective Java item #(我不记得了):了解和使用这些库。
You can use a Listand use the toArraymethod:
您可以使用 aList并使用该toArray方法:
List<String[]> twoDimension = new ArrayList<String[]>();
To convert it to an array you would use:
要将其转换为数组,您将使用:
String [][] theArray = twoDimension.toArray( new String[twoDimension.size()][] );
The trick is, the outer array is declared to hold String[]( string arrays ) which in turn can be dynamically created with another List<String>or, if your're parsing strings with the String.splitmethod.
诀窍是,外部数组被声明为保存String[](字符串数组),而后者又可以用另一个数组动态创建,List<String>或者,如果您正在使用该String.split方法解析字符串 。
Demo
演示
Focusing on the dynamic creation of the array and not in the parsing, here's an example on how does it works used in conjunction with String.split
专注于数组的动态创建而不是解析,这里有一个关于它如何工作的例子 String.split
// and array which contains N elements of M size
String input = "[[1],[2,3],[4,5,6,7],[8,9,10,11,12,13]]";
// Declare your dynamic array
List<String[]> multiDimArray = new ArrayList<String[]>();
// split where ],[ is found, just ignore the leading [[ and the trailing ]]
String [] parts = input.replaceAll("\[\[|\]\]","")
.split("\],\[");
// now split by comma and add it to the list
for( String s : parts ){
multiDimArray.add( s.split(",") ) ;
}
String [][] result = multiDimArray.toArray( new String[multiDimArray.size()][]);
There. Now your resultis a two dimensional dynamically created array containing : [[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13]]as expected.
那里。现在你result是一个二维动态创建的数组,包含 :[[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13]]正如预期的那样。
Here's a complete running demo, which also adds more regexp to the mix, to eliminate white spaces.
这是一个完整的运行演示,它还添加了更多的正则表达式,以消除空格。
I let you handle the other scenarios.
我让你处理其他情况。
回答by Salix alba
So I came across this question with code to extract coefficients from a polynomial with variable numbers of variables. So a user might
want the coefficient array for a polynomial in two variables 3 x^2 + 2 x yor it could be one with three variables. Ideally, you want a multiple dimension array which the user can easily interrogate so can be cast to
Integer[], Integer[][] etc.
所以我遇到了这个问题,代码是从变量数可变的多项式中提取系数。因此,用户可能需要包含两个变量的多项式的系数数组,3 x^2 + 2 x y或者它可能是包含三个变量的多项式。理想情况下,您需要一个用户可以轻松查询的多维数组,因此可以转换为 Integer[]、Integer[][] 等。
This basically uses the same technique as jdmichal's answer, using the Array.newInstance(obj.getClass(), size)method. For a multi dimensional arrays obj can be an array of one less dimension.
这基本上使用与 jdmichal 的答案相同的技术,使用Array.newInstance(obj.getClass(), size)方法。对于多维数组 obj 可以是少一维的数组。
Sample code with randomly created elements
带有随机创建元素的示例代码
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
public class MultiDimArray {
static Random rand = new Random();
/**
* Create an multi-dimensional array
* @param depth number of dimensions
* @return
*/
static Object buildArray(int depth) {
if(depth ==1) { // For 1D case just use a normal array
int size = rand.nextInt(3)+1;
Integer[] res = new Integer[size];
for(int i=0;i<size;++i) {
res[i] = new Integer(i);
}
return res;
}
// 2 or more dimensions, using recursion
int size = rand.nextInt(3)+1;
// Need to get first items so can find its class
Object ele0 = buildArray(depth-1);
// create array of correct type
Object res = Array.newInstance(ele0.getClass(), size);
Array.set(res, 0, ele0);
for(int i=1;i<size;++i) {
Array.set(res, i, buildArray(depth-1));
}
return res;
}
public static void main(String[] args) {
Integer[] oneD = (Integer[]) buildArray(1);
System.out.println(Arrays.deepToString(oneD));
Integer[][] twoD = (Integer[][]) buildArray(2);
System.out.println(Arrays.deepToString(twoD));
Integer[][][] threeD = (Integer[][][]) buildArray(3);
System.out.println(Arrays.deepToString(threeD));
}
}

