用Java中的多维数组进行Arrays.fill


71

如何在不使用循环的情况下用Java填充多维数组?我试过了:

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

这导致 java.lang.ArrayStoreException: java.lang.Double


4
@Caroline:如果您尝试使用0初始化2d数组,则无需这样做,因为分配数组时它已经使用0进行了初始化,并且不使用循环就无法初始化任何数组。您可以隐藏循环就像Arrays.fill一样。
艾米(Emil)

1
嘿,现在不要夸大了。他只想用Java API中的某种方法在一个步骤中将多维数组初始化为某个默认值。那就是他想说的没有循环。
Number945 '16

1
@ Number945我相信Caroline是个女性名字。
约翰·麦克莱恩

Answers:


99

这是因为adouble[][]double[]您无法分配0.0给它的数组(就像这样做double[] vector = 0.0)。实际上,Java没有真正的多维数组。

碰巧的0.0Java中double的默认值,因此当您从获取矩阵时,矩阵实际上已经被零填充了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);

这也足够Arrays.fill(arr, 0d);Arrays.fill(arr, (double)0);
Buhake Sindi 2011年

2
我得到,Exception in thread "main" java.lang.ArrayStoreException: java.lang.Double除非我遍历行。
aioobe

您为什么不尝试理解这个答案?在Java(以及C和C ++)中,没有多维数组!!!您的矩阵是一个简单的一维数组,其中每个“场”也是一个二维数组。您对Arrays.fill()的调用尝试将一个int(使其具有双重写入0.0而不是简单地为0)放入“矩阵”中,该方法不起作用。
2011年

为了挑剔,Arrays.fill()尝试在矩阵的每一中放置一个double 。
aioobe

73
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
你好 我只是想知道为什么您建议这种解决方案,而不是经典方案for。有动机吗?谢谢!
Maverik

94
由于问题中的以下词语:“不使用循环”。我的解决方案显然很荒谬,但确实可以正确回答问题。
trojanfoe 2011年

2
抱歉,错过了OP中的“不使用循环”功能:删除了我的不赞成票。也许您应该在回答中说过,该建议不应被认真对待。
巴特·基尔斯

25
不,这也是一个有趣的实验:正确答案可以得到多少票?
trojanfoe 2011年

2
@Bart:没问题-没关系:D
trojanfoe 2011年

11

根据Java 8,我们可以使用这种方式。

double[][] arr = new double[20][4]; Arrays.stream(arr).forEach(a -> Arrays.fill(a, 0));

我们可以用一种更好,更智能的方式在多维数组中初始化一个值。


从可读性的角度来看,这并不比for循环好。
陈建武

3
@JianwuChen OP要求无循环填充数组
Uri Loya

10

OP询问如何无循环解决此问题!由于某些原因,如今避免循环很流行。为什么是这样?有可能是一个实现,使用mapreducefilter,和朋友,和方法,如each隐藏循环和削减计划verbage并那种很酷的。真正好的Unix管道也是如此。或jQuery代码。事情看起来很好,没有循环。

但是Java有map方法吗?并非如此,但是我们可以Function使用evalorexec方法来定义一个接口。这不太困难,将是一个很好的练习。它可能很昂贵,并且实际上没有使用。

没有循环的另一种方法是使用尾递归。是的,这很愚蠢,也没有人会在实践中使用它,但是它确实表明,在这种情况下,循环很好。不过,仅为了展示“另一个免费循环示例”并获得乐趣,这里是:

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的问题时,没有明确的循环。


感谢您的所有解决方案!为什么我不想使用循环?我一直在寻找一种简单的解决方案,像在MATLAB中一样,生成一个零的nbyn矩阵。
卡罗琳

这可能仍然会导致堆栈溢出,因为Java不支持尾递归,因此循环肯定>递归。
kevinji

我将告诉您为什么它“可以避免循环流行”。每个人和他的兄弟都幻想自己是一个Linux内核程序员。看一下代码,您会发现循环之间的距离很短;人们拥有手工编码的测试和分支,并且代码中充满了goto。这在1974年的早期UNIX内核中是有道理的,当时可以合理地认为编译器为循环生成了次优的代码,但这在2016年非常适用。但是,每个人也认为这看起来非常高级,尤其是如果他将带有inane注释的代码,并具有荷兰姓。
布鲁斯·戴维·威尔纳

4

如何在不使用循环的情况下用Java填充多维数组?

多维数组只是数组的数组,fill(...)并不检查数组的类型和您传递的值(此责任在开发人员身上)。

因此,如果不使用循环,就无法合理地填充多维数组。

请注意,与C或C ++之类的语言不同,Java数组是对象,而在多维数组中,除最后一级外,所有数组都包含对其他Array对象的引用。我对此不是100%的确定,但是很可能它们分布在内存中,因此您不能只填充没有循环的连续块,就像C / C ++可以做到的那样。


4

作为答案的扩展,我找到了这篇文章,但希望填充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);
        }
    }
};

1

有时我们所有人都不希望有一个
<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}'s 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}'s 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}'s 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);
}


1

Arrays.fill仅适用于一维数组

java.util.Arrays的来源:

public static void fill(Object[] a, Object val) {
        int i = 0;

        for(int len = a.length; i < len; ++i) {
            a[i] = val;
        }

使用自己的循环进行初始化数组


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

我希望这做得好


这根本做不好!只需添加maze[2][2] = 'X';之后fillArray(maze, fillArray(maze[0], '?'));,您就会感到很大的惊喜。问题是您仅创建一行的一个实例,并且引用了10次。您丢弃创建的原始10行中的9行。
Florian F

而且它不能赢得int[][]数组。Character[][]之所以Character可以使用它,是因为它是一个对象。
Florian F

0

使用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][]);

0

简而言之,java不提供此类API。您需要遍历循环,并使用fill方法可以用一个循环填充2D数组。

      int row = 5;
      int col = 6;
      int cache[][]=new int[row][col];
      for(int i=0;i<=row;i++){
          Arrays.fill(cache[i]);
      }

他想在不使用Loop的情况下实现这一点,而您的答案使用Loop来解决问题。
surendrapanday

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

5
这行代码使每一行都指向相同的存储块,即更改arr [1] [5]也将更改arr [100] [5]。
minhle_r7
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.