Подтвердить что ты не робот

Arrays.fill с многомерным массивом в Java

Как заполнить многомерный массив в Java без использования цикла? Я пробовал:

double[][] arr = new double[20][4];
Arrays.fill(arr, 0);

В результате получается java.lang.ArrayStoreException: java.lang.Double

Спасибо заранее!

4b9b3361

Ответ 1

Это связано с тем, что 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);

Ответ 2

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

Ответ 3

ОП спросил, как решить эту проблему без цикла! По какой-то причине в наши дни модно избегать циклов. Почему это? Вероятно, существует осознание того, что использование 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 нет явных циклов.

Ответ 4

как я могу заполнить многомерный массив в Java без использования цикла?

Многомерные массивы - это всего лишь массивы массивов, а fill(...) не проверяет тип массива и значение, которое вы передаете (эта ответственность лежит на разработчике).

Таким образом, вы не можете достаточно хорошо заполнить многомерный массив без использования цикла.

Помните о том, что в отличие от языков, таких как C или С++, массивы Java являются объектами, а в многомерных массивах все, кроме последнего уровня, содержат ссылки на другие объекты Array. Я не уверен в этом на 100%, но, скорее всего, они распределены по памяти, поэтому вы не можете просто заполнить непрерывный блок без цикла, как это позволял бы C/С++.

Ответ 5

Как расширение ответа, я нашел этот пост, но хотел заполнить 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);
        }
    }
};

Ответ 6

Не все ли мы иногда хотели бы, чтобы <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);
}

Ответ 7

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

Надеюсь, это хорошо.

Ответ 8

Используя 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][]);

Ответ 9

Arrays.fill(arr, new double[4]);