Как заполнить многомерный массив в Java без использования цикла? Я пробовал:
double[][] arr = new double[20][4];
Arrays.fill(arr, 0);
В результате получается java.lang.ArrayStoreException: java.lang.Double
Спасибо заранее!
Как заполнить многомерный массив в Java без использования цикла? Я пробовал:
double[][] arr = new double[20][4];
Arrays.fill(arr, 0);
В результате получается java.lang.ArrayStoreException: java.lang.Double
Спасибо заранее!
Это связано с тем, что double[][]
представляет собой массив double[]
, который вы не можете назначить 0.0
(это будет как делать double[] vector = 0.0
). Фактически, Java не имеет истинных многомерных массивов.
Как это бывает, 0.0
является значением по умолчанию для удвоений в Java, поэтому на самом деле матрица будет заполнена нулями, когда вы получите ее от new
. Однако, если вы хотите заполнить его, скажем, 1.0
, вы можете сделать следующее:
Я не верю, что API предоставляет метод для решения этой проблемы без использования цикла. Однако достаточно просто сделать это с помощью цикла for-each.
double[][] matrix = new double[20][4];
// Fill each row with 1.0
for (double[] row: matrix)
Arrays.fill(row, 1.0);
double[][] arr = new double[20][4];
Arrays.fill(arr[0], 0);
Arrays.fill(arr[1], 0);
Arrays.fill(arr[2], 0);
Arrays.fill(arr[3], 0);
Arrays.fill(arr[4], 0);
Arrays.fill(arr[5], 0);
Arrays.fill(arr[6], 0);
Arrays.fill(arr[7], 0);
Arrays.fill(arr[8], 0);
Arrays.fill(arr[9], 0);
Arrays.fill(arr[10], 0);
Arrays.fill(arr[11], 0);
Arrays.fill(arr[12], 0);
Arrays.fill(arr[13], 0);
Arrays.fill(arr[14], 0);
Arrays.fill(arr[15], 0);
Arrays.fill(arr[16], 0);
Arrays.fill(arr[17], 0);
Arrays.fill(arr[18], 0);
Arrays.fill(arr[19], 0);
ОП спросил, как решить эту проблему без цикла! По какой-то причине в наши дни модно избегать циклов. Почему это? Вероятно, существует осознание того, что использование map
, reduce
, filter
и друзей, а также методы, подобные each
, скрывают петли и сокращают программные слова и выглядят классно. То же самое касается действительно сладких конвейеров Unix. Или код jQuery. Вещи просто отлично смотрятся без петель.
Но есть ли у Java метод map
? Не совсем, но мы можем определить один с интерфейсом Function
с помощью метода eval
или exec
. Это не слишком сложно и будет хорошим упражнением. Это может быть дорогостоящим и не использоваться на практике.
Другой способ сделать это без цикла - использовать хвостовую рекурсию. Да, это отчасти глупо, и никто не будет использовать его на практике, но он показывает, может быть, что петли в этом случае прекрасны. Тем не менее, просто для того, чтобы показать "еще один бесплатный пример цикла" и повеселиться, вот что:
import java.util.Arrays;
public class FillExample {
private static void fillRowsWithZeros(double[][] a, int rows, int cols) {
if (rows >= 0) {
double[] row = new double[cols];
Arrays.fill(row, 0.0);
a[rows] = row;
fillRowsWithZeros(a, rows - 1, cols);
}
}
public static void main(String[] args) {
double[][] arr = new double[20][4];
fillRowsWithZeros(arr, arr.length - 1, arr[0].length);
System.out.println(Arrays.deepToString(arr));
}
}
Это не очень, но в ответ на вопрос OP нет явных циклов.
как я могу заполнить многомерный массив в Java без использования цикла?
Многомерные массивы - это всего лишь массивы массивов, а fill(...)
не проверяет тип массива и значение, которое вы передаете (эта ответственность лежит на разработчике).
Таким образом, вы не можете достаточно хорошо заполнить многомерный массив без использования цикла.
Помните о том, что в отличие от языков, таких как C или С++, массивы Java являются объектами, а в многомерных массивах все, кроме последнего уровня, содержат ссылки на другие объекты Array
. Я не уверен в этом на 100%, но, скорее всего, они распределены по памяти, поэтому вы не можете просто заполнить непрерывный блок без цикла, как это позволял бы C/С++.
Как расширение ответа, я нашел этот пост, но хотел заполнить 4-мерный массив. Исходный пример - это только двумерный массив, но вопрос говорит о "многомерности". Я не хотел публиковать новый вопрос для этого...
Вы можете использовать один и тот же метод, но вам нужно вложить их, чтобы в итоге вы попали в одномерный массив.
fourDArray = new float[10][10][10][1];
// Fill each row with null
for (float[][][] row: fourDArray)
{
for (float[][] innerRow: row)
{
for (float[] innerInnerRow: innerRow)
{
Arrays.fill(innerInnerRow, -1000);
}
}
};
Не все ли мы иногда хотели бы, чтобы
<T>void java.util.Arrays.deepFill(T[]…multiDimensional)
. Проблемы начинаются с
Object threeByThree[][] = new Object[3][3];
threeByThree[1] = null;
и threeByThree[2][1] = new int[]{42};
является совершенно законным.
(Если только Object twoDim[]final[]
было законным и четко определено...)
(Использование одного из общедоступных методов снизу хранит циклы из вызывающего исходного кода.
Если вы настаиваете на том, чтобы вообще не использовать петли, замените петли и вызов на Arrays.fill()
(!) С помощью рекурсии.)
/** Fills matrix {@code m} with {@code value}.
* @return {@code m} dimensionality.
* @throws java.lang.ArrayStoreException if the component type
* of a subarray of non-zero length at the bottom level
* doesn't agree with {@code value} type. */
public static <T>int deepFill(Object[] m, T value) {
Class<?> components;
if (null == m ||
null == (components = m.getClass().getComponentType()))
return 0;
int dim = 0;
do
dim++;
while (null != (components = components.getComponentType()));
filler((Object[][])m, value, dim);
return dim;
}
/** Fills matrix {@code m} with {@code value}.
* @throws java.lang.ArrayStoreException if the component type
* of a subarray of non-zero length at level {@code dimensions}
* doesn't agree with {@code value} type. */
public static <T>void fill(Object[] m, T value, int dimensions) {
if (null != m)
filler(m, value, dimensions);
}
static <T>void filler(Object[] m, T value, int toGo) {
if (--toGo <= 0)
java.util.Arrays.fill(m, value);
else
for (Object[] subArray : (Object[][])m)
if (null != subArray)
filler(subArray, value, toGo);
}
public static Object[] fillArray(Object[] arr,Object item){
Arrays.fill(arr, item);
return arr;
}
Character[][] maze = new Character[10][10];
fillArray(maze, fillArray(maze[0], '?'));
for(int i = 0;i<10;i++){
System.out.println();
for(int j = 0;j<10;j++){
System.out.print(maze[i][j]);
}
}
Надеюсь, это хорошо.
Используя Java 8, вы можете объявить и инициализировать двумерный массив без использования (явного) цикла следующим образом:
int x = 20; // first dimension
int y = 4; // second dimension
double[][] a = IntStream.range(0, x)
.mapToObj(i -> new double[y])
.toArray(i -> new double[x][]);
Это приведет к инициализации массивов со значениями по умолчанию (0.0
в случае double
).
Если вы хотите явно определить значение заливки, которое будет использоваться, вы можете добавить в DoubleStream
:
int x = 20; // first dimension
int y = 4; // second dimension
double v = 5.0; // fill value
double[][] a = IntStream
.range(0, x)
.mapToObj(i -> DoubleStream.generate(() -> v).limit(y).toArray())
.toArray(i -> new double[x][]);
Arrays.fill(arr, new double[4]);