英文:
Is there any way to flatten these nested IntStreams into one? Is there shorter way?
问题
我将4个嵌套的for
循环改为了嵌套的IntStream
,但这个解决方案看起来不太好。我不知道如何使它更简短?我应该以某种方式使用flatmap
吗?
IntStream.range(0, totalCluster).forEach(numCluster -> {
writeToFile("Cluster__________________________" + numCluster);
IntStream.range(0, totalAgency).forEach(numAgency -> {
writeToFile("\n\tCluster_" + numCluster + "_Agency_" + numAgency);
IntStream.range(0, totalProgramArea).flatMap(numProgramArea ->
IntStream.range(0, totalUsers).mapToObj(numUser ->
"\n\t\t\tAgency_" + numAgency + "_" + "ProgramArea_" + numProgramArea + "_User_" + numUser))
.forEach(this::writeToFile);
}));
});
});
英文:
I changed 4 nested for
loops to nested IntStream
but this solution doesn't look good. I don't know how to make it shorter? Should I use flatmap
in some way?
IntStream.range(0, totalCluster).forEach(numCluster ->{
writeToFile("Cluster__________________________" + numCluster);
IntStream.range(0, totalAgency).forEach(numAgency ->{
writeToFile("\n\tCluster_" + numCluster + "_Agency_" + numAgency);
IntStream.range(0, totalProgramArea).forEach(numProgramArea ->IntStream.range(0, totalUsers).forEach(numUser ->{
writeToFile("\n\t\t\tAgency_" + numAgency + "_" + "ProgramArea_" + numProgramArea + "_User_" + numUser);
}));
});
});
答案1
得分: 3
你可能在询问以下代码结构:
IntStream.range(0, 2)
.flatMap(i -> IntStream.range(0, 2))
.flatMap(i -> IntStream.range(0, 2))
.forEach(i -> /*... 内部循环逻辑 ...*/ );
然而,如果你需要在最内层逻辑中获得每个外部循环的每次迭代的索引,没有比较好的方法来实现。对于你的问题的答案是 - 传统的 for 循环在这里效果更好。
不过,这里是一个示例(为了提高可读性,我减少了混乱):
IntStream.range(0, totalClusters).boxed()
.flatMap(i -> IntStream.range(0, totalAgencies).mapToObj(j -> new int[]{i,j}))
.flatMap(k -> IntStream.range(0, totalAreas).mapToObj(j -> new int[]{k[0],k[1],j}))
.forEach(o -> System.out.println(Arrays.toString(o)));
它会打印出:
[0, 0, 0]
[0, 0, 1]
...
[1, 1, 1]
这段代码的问题在于,你必须在堆上分配 int 数组,而不是使用堆栈上的循环计数器。我只是出于简单起见使用了 int[]
,这不是一个好的实践,实际上最好使用一些上下文对象。
你可以从这里得到解决方案的想法。
现在,人们经常问是否有一种适当的函数式方法来处理嵌套的 for 循环。在像 Haskell 这样的语言中,你会使用类似以下方式,因为列表是单子(或列表推导式):
do
i <- [0..2]
j <- [0..3]
return $ i*100 + j
在 Java 中,你绝对可以采用类似的 do-notation 逻辑,通过创建自己的函数组合库来实现。尽管可能实现,但与 Scala 不同,Java 的语法在这种特定情况下不如传统的 for 循环好看。
英文:
You are probably asking about a construct in form
IntStream.range(0, 2)
.flatMap(i -> IntStream.range(0, 2))
.flatMap(i -> IntStream.range(0, 2))
.forEach(i -> /*... inner loop logic here ..*/ );
However, if you need the index of each iteration of every outer loop inside the innermost logic, there is no nice way of doing it. The answer to your question is - old fashioned for loops work better here.
Still, here is one example (I reduced clutter to improve readability):
IntStream.range(0, totalClusters).boxed()
.flatMap(i -> IntStream.range(0, totalAgencies).mapToObj(j -> new int[]{i,j})).
.flatMap(k -> IntStream.range(0, totalAreas).mapToObj(j -> new int[]{k[0],k[1],j}))
.forEach(o -> System.out.println(Arrays.toString(o)));
It prints
[0, 0, 0]
[0, 0, 1]
...
[1, 1, 1]
The problem with this code is that you have to allocate int arrays on heap instead of using loop counters from stack. I only used int[]
for simplicity, it is not a good practice, in reality it is better to use some context object.
You can derive an idea of a solution from here.
Now, people often ask if there is a proper functional way of dealing with nested for loops. In a language like Haskell, you would use something like this, because lists are monads (or list comprehensions):
do
i <- [0..2]
j <- [0..3]
return $ i*100 + j
You can definitely go for similar do-notation logic in Java, by creating your own library of function combinators. Even though it is possible, unlike in Scala, syntax of Java prevents the end result from looking better than old fashioned for loops, in this particular case.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论