创建初始重复数据的二维字符串数组的最有效方法是啥?

Posted

技术标签:

【中文标题】创建初始重复数据的二维字符串数组的最有效方法是啥?【英文标题】:What is the most efficient way to create a 2d string array of initally repetitive data?创建初始重复数据的二维字符串数组的最有效方法是什么? 【发布时间】:2021-05-29 06:14:31 【问题描述】:

在 Python 中,通常要定义所述游戏板,我会使用以下代码:

board = [['0','0','0','0','0','0','0','0','0','0'] for i in range(10)]

但是,到目前为止,我能够找到产生相同结果的唯一方法是使用 Java:

public static String[][] board = 
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0",
        "0","0","0","0","0","0","0","0","0","0";

当然必须有更有效的方法来做到这一点。我知道如果它是整数,我可以有效地做到这一点,但考虑到这种情况,它必须是字符串。我原以为 for 循环也可以应用,但我似乎找不到合适的语法;也许它不适用于Java。有什么建议吗?

【问题讨论】:

【参考方案1】:

您可以遍历每一行并使用Arrays.fill

public static String[][] board = new String[rows][cols];
static 
    for (String[] row : board) Arrays.fill(row, "0");

Demo

【讨论】:

【参考方案2】:

您可以使用嵌套的for 循环来创建 10 行和 10 列。因此,在第一个循环(创建一个“行”)中,您需要添加另一个循环来填充“列”。

String[][] board = new String[10][10];

// 10 rows
for (int i = 0; i < 10; i++) 
    // 10 columns
    for (int j = 0; j < 10; j++) 
        // Set the value of this row/column
        board[i][j] = "0";
    

这显然不如 Python 的单行解决方案优雅,但它可以满足您的需求。

还有其他方法可以做到这一点(例如在每个循环中将一个完整的 10 位数组添加到 board 数组),但我发现这对于可扩展性和可读性来说是最好的。


为了更清楚起见,如果您将来可能需要更改行数或列数,最好将这些值移动到变量中并改用它们:

int rows = 10;
int cols = 10;

String[][] board = new String[rows][cols];

for (int i = 0; i < rows; i++) 
    for (int j = 0; j < cols; i++) 
        board[i][j] = "0";
    

这样你只需要更新变量而不是修改for循环和数组声明。

【讨论】:

哦,我明白了。所以,我将板定义为 10x10,然后返回并将值重置为“0”,允许它们用作字符串......对吗? 假设您提前知道确切的尺寸,是的。不过,到目前为止,这里的其他答案在代码行方面可能更有效。这真的取决于什么对你来说更具可读性。 它始终是相同的确切尺寸是的。唯一要改变的是他们的价值观。可读性在这里有些重要,我相信您的解决方案似乎是我见过的最好的。非常感谢您的解决方案;事实证明,在 Python 和 Java 之间转换很困难。 这基本上是教科书的迭代方法。如果您打算使用嵌套的 for 循环,使用经典的迭代样式直接对数组值进行操作,那么这将尽可能简单明了。 @M.Justin 是的,这正是我想要的。这是将被审查的代码,不幸的是,我不得不向没有经验的人逐行解释,所以这可能是我能找到的最佳解决方案。【参考方案3】:

你可以这样做。因为Strings 是不可变的,所以在这里使用clone() 是安全的。感谢@iota 推荐setAll

int n = 10;
String[][] arr = new String[n][n];
Arrays.fill(arr[0], "0");
Arrays.setAll(arr, i->arr[0].clone());


for(String[] a : arr) 
    System.out.println(Arrays.toString(a));

打印

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

【讨论】:

试试arr[1][2] = "2"。该数组中恰好有两个实例String[10]:第一个子数组(原始)和第二个子数组(克隆)重复直到结束(字符串是不可变的,(子)数组不是) @WJS 你可以使用Arrays.setAll来避免这个问题:String[] row = arr[0].clone();Arrays.setAll(arr, i -&gt; row.clone()); @WJS 没问题。【参考方案4】:

以下是基于stream 的解决方案,该解决方案使用函数式样式而非迭代式样式:

return Stream.generate(() -> 
                Collections.nCopies(10, "0").toArray(String[]::new))
        .limit(10)
        .toArray(String[][]::new);

请注意,根据可读性等要求,可能会认为经典的迭代样式更可取。

说明

Collections.nCopies(10, "0") 创建一个包含 10 个 "0" 值的 List&lt;String&gt;。使用Collection.toArray(IntFunction) 将其转换为String 数组。这需要一个IntFunction,它会生成一个给定长度的数组。 String[]::new 是一个 constructor lambda,它实现了 IntFunction&lt;String[]&gt;,创建了一个给定长度的数组。

Stream.generate 通过调用给定的Supplier 创建每个元素的无限流。在这种情况下,供应商创建了前面提到的 10 元素长列表,结果是 Stream&lt;String[]&gt;。使用了生成器,而不是 Collections.nCopies,因为 String[][] 中的每个 String[] 都需要是不同的对象。

无限流仅限于使用Stream.limit(10) 的十个元素。

最后,使用Stream.toArray(IntFunction)Stream&lt;String[]&gt; 收集到String[][] 中,其工作方式与已经描述的Collection.toArray 方法相同。

【讨论】:

【参考方案5】:

这是 for 循环和手动创建一行单元格的混合体。

String[][] board = new String[10][];
for (int i = 0; i < 10; i++) 
    board[i] = new String[]"0","0","0","0","0","0","0","0","0","0";

【讨论】:

【参考方案6】:

String#repeat 从 11 开始

String[][] board = new String[10][];
    Arrays.setAll - 每行重复 0 十次并拆分为一个数组:
    Arrays.setAll(board, i -> "0".repeat(10).split(""));
    
    Arrays.fill - 在这种情况下,结果是一样的:
    Arrays.fill(board, "0".repeat(10).split(""));
    

输出:

Arrays.stream(board).map(Arrays::toString).forEach(System.out::println);
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

另见:How can I fill this 2D array with X characters?

【讨论】:

以上是关于创建初始重复数据的二维字符串数组的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 Go 中访问二维数组中的相邻元素的最有效方法是啥?

从 .txt 文件中读取未知大小的整数二维数组的最有效方法是啥?

识别和删除数组中重复项的最有效方法是啥?

创建零填充 JavaScript 数组的最有效方法是啥?

使用 C#,将包含二进制数据的字符串转换为字节数组的最有效方法是啥

声明混合类型的多维数组的最有效方法是啥?