使用Java中的多维数组填充数组

问题描述:

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

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

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

提前感谢!

+2

但为什么不使用一个循环? –

+2

@Caroline:如果你想用0初始化2d数组,你不需要这样做,因为当你分配数组时,它已经被初始化为0,并且你不能在没有使用循环的情况下初始化任何数组。你可以隐藏像Arrays.fill一样在函数中循环。 – Emil

+1

嘿,大家现在不要夸大它。他所需要的只是Java API中的一些方法,可以在单步骤中将多维数组初始化为某个默认值。这就是他想要说的没有循环。 –

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

+61

由于问题中有以下词语:“不使用循环”。我的解决方案显然很荒谬,但它确实正确地回答了这个问题。 – *foe

+2

对不起,错过了OP中的“不使用循环”:删除了我的倒票。也许你应该在你的回答中说出这个建议不应该被认真对待。 –

这是因为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); 
+0

这个就够用了'Arrays.fill(arr,0d);'或'Arrays.fill(arr,(double)0);' –

+2

我得到'线程“main”java.lang.ArrayStoreException:java.lang.Double'中的异常,除非我循环遍历行。 – aioobe

+0

你为什么不试着去理解这个答案?在Java(和C和C++)中没有多维数组!你的矩阵是一个简单的一维数组,每个“场”又是一个维数组。你对Arrays.fill()的调用会尝试将一个_int_(有一个双重写入0.0而不是简单的0)放入“矩阵”中,这不起作用。 –

我怎样才能填平Java多维数组,而不使用循环?

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

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

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

OP问如何解决这个问题没有回路!由于某些原因,现在很流行避免循环。为什么是这样?可能有一种认识,使用map,reduce,filter和朋友,以及像each这样的方法可以隐藏循环并减少程序的运行时间,并且非常酷。对于非常好的Unix管道也是一样。或者jQuery代码。事情看起来很棒,没有循环。

但Java是否有map方法?并非如此,但我们可以使用evalexec方法将接口定义为Function。这不是太难,会是一个很好的练习。它可能是昂贵的,并没有在实践中使用。

另一种方法做到这一点没有循环是使用尾递归。是的,这实在是太傻了,实际上也没有人会用它,但它确实表明,在这种情况下,循环很好。然而,只是为了显示“另一免费循环示例”和有乐趣,这里是:

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

+0

+1,不是解决方案,而是一个非常好的答案 – Dragon8

+0

感谢您的所有解决方案! 我不想使用循环的原因?我正在寻找一个简单的解决方案,用于生成像MATLAB一样的零的n×n矩阵。 – Caroline

+0

这可能仍然会导致堆栈溢出,因为Java没有尾递归支持,所以肯定会循环递归。 – mc10

作为答案的延伸,我找到了这篇文章,但正在寻找填充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); 
     } 
    } 
}; 

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

该行使每一行都指向相同的内存块,即更改arr [1] [5]也会更改arr [100] [5]。 –

不要我们有时会希望能有一个
<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); 
} 

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.0double的情况下)。

在要明确定义要使用的填充值的情况下,您可以添加在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][]);