Возможно ли динамическое построение многомерного массива в Java?
Предположим, что у нас есть код Java:
Object arr = Array.newInstance(Array.class, 5);
Будет ли это работать? В качестве дальнейшего примечания, что, если мы должны были попробовать что-то вроде этого:
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);
Будет ли arr1 быть двумерным массивом, эквивалентным:
String[2][4] arr1;
Как насчет этого: что, если мы не знаем размеры этого массива до времени выполнения?
Изменить: если это помогает (я уверен, что это будет...), мы пытаемся проанализировать массив неизвестных измерений из строки формы
[value1, value2, ...]
или
[ [value11, value12, ...] [value21, value22, ...] ...]
И так далее
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);
И так далее. Он просто должен быть гигантским вложенным массивом объектов
Ответы
Ответ 1
На самом деле это можно сделать в java. (Я немного удивлен, что должен сказать.)
Отказ от ответственности; Я никогда не хочу видеть этот код нигде, кроме как ответа на этот вопрос. Я настоятельно рекомендую вам использовать List
s.
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));
}
}
Результат:
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]]]
Ответ 2
Массивы являются безопасными по типу в java - это относится к простым массивам и "многомерным" массивам, т.е. массивам массивов.
Если глубина вложенности является переменной во время выполнения, то лучше всего использовать массив, который соответствует известной минимальной глубине вложенности (предположительно 1.). Элементы в этом массиве, которые затем либо являются простыми элементами, либо если требуется дополнительное вложение, другой массив. Массив Object [] позволит вам сделать это, поскольку сами вложенные массивы также считаются объектами и поэтому вписываются в систему типов.
Если вложенность полностью регулярна, вы можете вытеснить эту закономерность и создать соответствующий многомерный массив, используя Array.newInstance(String.class, dimension1, dimension2, ...)
. Если вложение нерегулярно, вам будет лучше использовать вложенные списки, которые позволят создать "зубчатую" структуру и динамический размер. У вас может быть зубчатая структура при расчете генериков. Дженерики не могут использоваться, если структура зазубрена, поскольку некоторые элементы могут быть простыми элементами, а другие элементы могут быть дополнительными вложенными списками.
Ответ 3
Хорошо, если вы не уверены в размерах массива, тогда следующий метод не будет работать. Однако, если вы знаете размеры, не используйте отражение. Выполните следующие действия:
Вы можете динамически строить 2d массивы намного проще, чем это.
int x = //some value
int y = //some other value
String[][] arr = new String[x][y];
Это будет "динамически" создавать массив x
на y
2d.
Ответ 4
Таким образом, вы можете передавать несколько измерений до 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]
Другой вариант - создать их снизу, используя 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("]");
}
}
Ответ 5
В качестве дальнейшего примечания, что, если мы должны были попробовать что-то вроде этого:
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);
...
Нет, вы не можете установить значение 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)
Ответ 6
Эффективный элемент Java # (я не помню):
Знать и использовать библиотеки!
Вы можете использовать List
и использовать метод toArray
:
List<String[]> twoDimension = new ArrayList<String[]>();
Чтобы преобразовать его в массив, вы должны использовать:
String [][] theArray = twoDimension.toArray( new String[twoDimension.size()][] );
Трюк заключается в том, что внешний массив объявлен как содержащийся String[]
(строковые массивы), который, в свою очередь, может быть динамически создан с помощью другого List<String>
или, если ваш синтаксический анализ строк с помощью метода String.split
.
Demo
Сосредоточив внимание на динамическом создании массива, а не на синтаксическом анализе, здесь приведен пример того, как он работает в сочетании с 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()][]);
Там. Теперь ваш result
представляет собой двумерный динамически созданный массив, содержащий: [[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13]]
, как и ожидалось.
Здесь полная демонстрационная версия, которая также добавляет больше регулярных выражений в микс, чтобы исключить пробелы.
Я разрешаю вам обрабатывать другие сценарии.
Ответ 7
Итак, я наткнулся на этот вопрос с кодом, чтобы извлечь коэффициенты из полинома с переменными числами переменных. Таким образом, пользователь может
требуется массив коэффициентов для многочлена от двух переменных 3 x^2 + 2 x y
или он может быть одним с тремя переменными. В идеале вы хотите, чтобы массив с несколькими измерениями, который пользователь может легко опросить, может быть отброшен
Integer [], Integer [] [] и т.д.
В основном используется тот же метод, что и jdmichal, используя метод Array.newInstance(obj.getClass(), size)
. Для многомерных массивов obj может быть массивом из одного меньшего размера.
Пример кода со случайно созданными элементами
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));
}
}