【问题标题】:Convert classic nested loops with multiple if/else with Java streams使用 Java 流转换具有多个 if/else 的经典嵌套循环
【发布时间】:2020-05-19 21:06:54
【问题描述】:

我需要一些关于在此处使用 Java Streams 可以做什么的指导。我有 test[][] 对象的二维数组,其中包含行、列和值。为了产生不同的表示,我循环并手动附加不同的字符来做到这一点。

public class Test{
    private Point[][] test;   // like a rectangle
    ...
}

public String someFunction() {
    StringBuilder result = new StringBuilder(150);
    for (int row = 0; r < 10; row++) {
        for (int col = 0; c < 15; col++) {
            if (test[row][col].getVal() == 1) {
                result.append('L');
            } else if (test[row][col].getVal() == 2) {
                result.append('M');
            } else if (test[row][col].getVal() == 10) {
                result.append('N');
            } else {
                result.append(' ');
            }
        }
        result.append('\n');
    }
    return result.toString();
 }

另外,通常流如何与 2 个循环一起工作,一些很好的例子会很有帮助。

【问题讨论】:

  • 你能分享test的定义吗?字符串比较也应该用equals完成,而不是==
  • @Michael - 已更正!只是为了显示样本比较
  • @azro - 已更正!并补充说,我需要一些想法如何替换这些循环和 ifs .. 使用流还是比当前的更努力和更混乱?
  • 请记住,仅仅因为流“较新”,并不意味着它总是更好或更清晰地使用。

标签: java java-8 java-stream


【解决方案1】:

为了简化这段代码,你可以使用for-each循环,这样你就不需要处理索引了

public String someFunction() {
    for (C[] row : test) {
        for (C item : row) {
            if (item.getVal() == 1) {
                result.append('L');
            } else if (item.getVal() == 2) {
                result.append('M');
            } else if (item.getVal() == 10) {
                result.append('N');
            } else {
                result.append(' ');
            }
        }
        result.append('\n');
    }
    return result.toString();
}

使用 Stream 版本不会赢得任何东西,因为您只是在迭代数组做简单的事情,所以经典循环很好,但它就是这样

public static String someFunction() {
    return Arrays.stream(test)
            .map(row -> Arrays.stream(row).map(item -> {
                switch (item.getVal()) {
                    case 1:
                        return "L";
                    case 2:
                        return "M";
                    case 10:
                        return "N";
                    default:
                        return " ";
                }
            }).collect(Collectors.joining()))
            .collect(Collectors.joining("\n"));
}

如果你想看的话,带索引的 Stream 版本

public String someFunction() {
    return IntStream.range(0, test.length).mapToObj(rowIdx -> IntStream.range(0, test[rowIdx].length).mapToObj(colIdx -> {
        switch (test[rowIdx][colIdx].getVal()) {
                    ...
        }
    }).collect(Collectors.joining())).collect(Collectors.joining("\n"));
}

【讨论】:

  • @Michael 不再这么认为 OP 的编辑
【解决方案2】:

我将 int 映射到 char 的解决方案是使用 char 数组。

char[] intToChar = {' ', 'L', 'M', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'N};

这可以用一个简单的赋值替换ifswitch这一系列

这可以通过字符串和charAt(i)方法变得更简单

【讨论】:

    【解决方案3】:

    这是 Azro 的回答略有不同,因为我基本上已经写好了。

    如果索引很重要(即由于某种原因,您只想对完整“网格”的一部分执行计算),那么Arrays.stream 有另一个签名,您可以在其中指定这些,就像您在答案中所做的那样.

    从 Java 14 开始,您可以使用 switch 表达式使从点值到字符的转换更好一点。

    您也可以以与迭代示例类似的方式使用StringBuilders。 Collectors.joining 以类似的方式工作,但它无法预先分配正确的空间量。几乎可以肯定与 150 个字符无关,但无论如何我认为这是一个有趣的例子。

    return Arrays.stream(test, 0, 10)
        .map(row -> Arrays.stream(row, 0, 15)
            .map(ValueSource::getVal)
            .map(val -> switch(val) {
                case 1 ->  'L';
                case 2 ->  'M';
                case 10 -> 'N';
                default -> ' ';
            })
            .collect(Collector.of(() -> new StringBuilder(row.length), StringBuilder::append, StringBuilder::append))
        )
        .collect(Collector.of(() -> new StringBuilder(150), StringBuilder::append, StringBuilder::append, StringBuilder::toString));
    

    【讨论】:

      猜你喜欢
      • 2022-01-19
      • 1970-01-01
      • 2020-10-15
      • 2018-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多