Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用流填充多维数组_Java_Arrays_Functional Programming_Java 8_Java Stream - Fatal编程技术网

Java 使用流填充多维数组

Java 使用流填充多维数组,java,arrays,functional-programming,java-8,java-stream,Java,Arrays,Functional Programming,Java 8,Java Stream,我是Java8新手,目前无法完全掌握流,是否可以使用流函数操作填充数组?这是一个示例代码,说明如何使用标准for循环执行此操作: public static void testForLoop(){ String[][] array = new String[3][3]; for (int x = 0; x < array.length; x++){ for (int y = 0; y < array[x].length; y++){

我是Java8新手,目前无法完全掌握流,是否可以使用流函数操作填充数组?这是一个示例代码,说明如何使用标准for循环执行此操作:

public static void testForLoop(){
    String[][] array = new String[3][3];
    for (int x = 0; x < array.length; x++){
        for (int y = 0; y < array[x].length; y++){
            array[x][y] = String.format("%c%c", letter(x), letter(y));
        }
    }               
}

public static char letter(int i){
    return letters.charAt(i);
} 
publicstaticvoidtestforloop(){
字符串[][]数组=新字符串[3][3];
对于(int x=0;x

如果可能的话,我将如何使用Stream?如果可能,是否方便(性能和可读性方面)?

有几种方法可以做到这一点

一种方法是在行和列索引上使用一对嵌套的
IntStreams

String[][] testStream() {
    String[][] array = new String[3][3];
    IntStream.range(0, array.length).forEach(x -> 
        IntStream.range(0, array[x].length).forEach(y -> 
            array[x][y] = String.format("%c%c", letter(x), letter(y))));
    return array;
}
另一种似乎很有希望的方法是使用
Array.setAll
而不是streams。这对于为一维数组生成值非常有用:您提供了一个函数,该函数可以从数组索引映射到要在数组中指定的值。例如,您可以这样做:

String[] sa = new String[17];
Arrays.setAll(sa, i -> letter(i));
不幸的是,多维数组不太方便。采用lambda的
setAll
方法,该lambda返回分配给该索引处数组位置的值。如果已创建多维数组,则较高维度已使用较低维度数组初始化。您不想分配给它们,但确实需要
setAll
的隐式循环行为

记住这一点,您可以使用
setAll
初始化多维数组,如下所示:

static String[][] testArraySetAll() {
    String[][] array = new String[3][3];
    Arrays.setAll(array, x -> {
        Arrays.setAll(array[x], y -> String.format("%c%c", letter(x), letter(y)));
        return array[x];
    });
    return array;
}
内部的
setAll
相当不错,但是外部的必须有一个lambda语句来调用内部的
setAll
,然后返回当前数组。不太漂亮


我不清楚这两种方法是否比典型的嵌套for循环更好。

最好的方法是将这两种方法结合起来

导致该解决方案的原因是,Java中的“填充多维数组”意味着“在外部数组上迭代”,然后“填充一维数组”,如
String[][]
在Java中只是
String[]
元素的数组。为了设置它们的元素,您必须迭代所有
String[]
元素,因为您需要索引来计算最终值,所以不能使用
Arrays.stream(array.forEach(…)
。因此,对于外部数组,遍历索引是合适的


对于内部数组,搜索的是修改(一维)数组的最佳解决方案。这里,
数组。setAll(…,…)
是合适的。

这里有一个解决方案,可以生成数组,而不是修改以前定义的变量:

String[][] array = 
    IntStream.range(0, 3)
             .mapToObj(x -> IntStream.range(0, 3)
                                     .mapToObj(y -> String.format("%c%c", letter(x), letter(y)))
                                     .toArray(String[]::new))
             .toArray(String[][]::new);

如果您想使用并行流,那么避免诸如修改变量(数组或对象)之类的副作用是非常重要的。它可能会导致竞争条件或其他并发问题。您可以在中了解更多信息-请参阅“无干扰、无状态行为和副作用”部分。

在围绕这一点进行工作和测试后,这是我的最佳选择:

IntStream.range(0, array.length).forEach(x -> Arrays.setAll(array[x], y -> builder.build2Dobject(x, y)));
(在具体情况下,我建议:

IntStream.range(0, array.length).forEach(x -> Arrays.setAll(array[x], y -> String.format("%c%c", letter(x), letter(y)));
对于3d阵列,它只是:

IntStream.range(0, array.length).forEach(x -> IntStream.range(0, array[x].length).forEach(y -> Arrays.setAll(array[x][y], z -> builder.build3Dobject(x, y, z))));
这是让程序选择最快选项的代码:

public static void fill2DArray(Object[][] array, Object2DBuilderReturn builder){
    int totalLength = array.length * array[0].length;
    if (totalLength < 200){
        for(int x = 0; x < array.length; x++){
            for (int y = 0; y < array[x].length; y++){
                array[x][y] = builder.build2Dobject(x, y);
            }
        }
    } else if (totalLength >= 200 && totalLength < 1000){
        IntStream.range(0, array.length).forEach(x -> Arrays.setAll(array[x], y -> builder.build2Dobject(x, y))); 
    } else {
        IntStream.range(0, array.length).forEach(x -> Arrays.setAll(array[x], y -> builder.build2Dobject(x, y))); 
    }
}
publicstaticvoidfill2darray(Object[][]数组,object2dbuilderreturnbuilder){
int totalLength=array.length*数组[0]。长度;
如果(总长度<200){
对于(int x=0;x=200和总长度<1000){
IntStream.range(0,array.length).forEach(x->array.setAll(array[x],y->builder.build2Dobject(x,y));
}否则{
IntStream.range(0,array.length).forEach(x->array.setAll(array[x],y->builder.build2Dobject(x,y));
}
}
功能界面:

@FunctionalInterface
public interface Object2DBuilderReturn<T> {
    public T build2Dobject(int a, int b);
}
@functioninterface
公共接口Object2DBuilderReturn{
公共T build2Dobject(inta、intb);
}

不太相关,但我想你指的是
array[x].length
用于内部循环。是的,我确实使用了循环的标准。您的代码对读者来说简单明了。尽管streams解决方案看起来很优雅,但我看不到它在这里添加了任何内容。@SaintHill,因为实际的代码使用了一个包含数万到数十万个不同对象的3d数组,我想测试流方法比循环的标准方法快:)稍微快一点,阵列的总大小优于正常流的200(这可能取决于处理器)。速度更快,总大小超过1000个并行流。(我使用的是QuadCore i5-3570k,64位实际上,这似乎比我自己找到的最终解决方案更复杂,但我应该测试哪一个更快。对-它的可读性不如其他解决方案,但它的优点是它不会修改外部变量,这在使用并行流时通常非常重要-很薄您可以在包文档(非干扰、无状态行为和副作用部分)中阅读更多关于这方面的内容。我正在试图理解我在这里缺少的内容。Arrays.setAll不是.mapToObj(…).toArray(…).toArray(…)的快捷方式吗?@AngeloAlvisi No,Arrays.setAll正在迭代传递的数组和给定函数生成的设置值。请查看源代码:
@FunctionalInterface
public interface Object2DBuilderReturn<T> {
    public T build2Dobject(int a, int b);
}