使用Java流转换具有多个if/else的经典嵌套循环

huangapple go评论73阅读模式
英文:

Convert classic nested loops with multiple if/else with Java streams

问题

我需要一些关于如何使用Java Streams 进行操作的指导。我有一个名为test[][]的二维数组对象,其中包含行、列和值信息。为了生成不同的表示形式,我通过循环遍历并手动附加不同的字符来执行操作。

public class Test {
    private Point[][] test;   // 类似一个矩形
    // ...
}

public String someFunction() {
    StringBuilder result = new StringBuilder(150);
    for (int row = 0; row < 10; row++) {
        for (int col = 0; col < 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();
}

此外,通常情况下,如何使用流(Streams)处理两层循环,以下是一些很好的示例将会很有帮助。

(注意:此处不提供具体的代码示例,只回答了关于如何使用流处理两层循环的一般性问题。)

英文:

I need some guidance on what can be done here using Java Streams. I have the 2D Arrray of test[][] object which holds row, col and value inside. in order to produce different representation, I loop through and manually append different characters to do that.

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

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

Also, Generally how does the streams work with 2 loops, some good examples would be great help.

答案1

得分: 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();
}

因为你只是在遍历数组进行简单的操作,所以使用流的版本不会带来什么好处,经典的循环方式很好,但是这里是用流的版本:

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"));
}

如果你想要看到带有索引的流版本,可以这样:

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"));
}
英文:

To simplify a bit this code, you can use for-each loops, this way you won't need to handle indexes

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

You won't win something by using the Stream version because you're doing easy thing just iterating an array so the classic loop is nice, but here it is

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

And if you want to see it, the Stream version with the indices

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

答案2

得分: 0

我的整数到字符映射解决方案是使用字符数组。

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

这可以用简单的赋值来替代一系列的ifswitch语句。

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

英文:

my solution for the mapping of int to char is to use char array.

char[] intToChar = {&#39; &#39;, &#39;L&#39;, &#39;M&#39;, &#39; &#39;, &#39; &#39;, &#39; &#39;, &#39; &#39;, &#39; &#39;, &#39; &#39;, &#39; &#39;, &#39;N};

this can replace the series of if or switch with a simple assignment

this can be made simpler with a String and the method charAt(i)

答案3

得分: 0

这是 Azro 的答案的略微变化,因为我基本上已经写过了。

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

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

您还可以以与迭代示例类似的方式使用 StringBuilderCollectors.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));
英文:

Here's a slight variation of Azro's answer, since I'd basically already written it.

If the indices are important (i.e. for some reason you want to perform the calculation only on a portion of the full "grid") then Arrays.stream has another signature where you can specify those, just as you did in your answer.

From Java 14, you can use switch expressions to make the conversion from point value to character a bit nicer.

You can also also use StringBuilders in a similar way as your iterative example. Collectors.joining works in a similar way but it is not able to pre-allocate the right amount of space. Almost certainly irrelevant for 150 characters, but I thought it made an interesting example anyway.

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

huangapple
  • 本文由 发表于 2020年4月7日 22:54:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/61082927.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定