我正在动态编程中练习,我也想在Lambda表达式中进行实验(阅读“学习如何编写Lambda表达式”).
让我们假设我正在研究两个矩阵:MatrixA [] []和MatrixB [] [].
我需要检查MatrixA中的所有单元格并逐步填充它们,同时填充MatrixB的一些条目.
这是我的代码:
int[][] A = new int[n][m];
String[][] B = new String[n][m];
for (int i=0; i<=n; ++i)
for(int j=0; j<=m; ++j){
if ( i==0 && j==0 ) A[i][j] = 0;
else if ( i==0 ) A[i][j] = j;
else if ( j==0 ) A[i][j] = i;
else {
if ( A[i-1][j-1] > A[i-1][j] ){
A[i][j] = A[i-1][j-1];
B[i][j] = "D";
} else {
A[i][j] = A[i-1][j];
B[i][j] = "T";
}
}
}
我想知道是否存在一些使用Lambda表达式对其进行编码的更紧凑的方法.不幸的是,我是Lambdas的新手,我不确定这个例子是否适合他们(或者在这里使用它们实际上很方便).
我找到了一些解决方案,建议使用IntStream,定义范围,并迭代每个元素:
IntStream.range(0, n)
.forEach( (i) -> {
IntStream.range(0,m)
.forEach( (j) -> {
// Body of the function.
})
});
但是,它似乎是一种更复杂的定义for循环的方法.
我正在寻找一种方法来检查两个元素的最大值(甚至可能检查它们是否相同,因此两者都是最大值)并根据哪个是修改两个矩阵的最大值.
有什么建议?
最佳答案 免责声明:我坚信最好的方法是坚持使用嵌套循环.
但是,如果你真的很好奇(就像我一样),这里有一种方法可以使用流和2个变量的递归函数.
首先,定义两个函数.函数A将一对整数(i,j)映射到整数,函数B将一对整数(i,j)映射到一个字符串:
enum Functions {
INSTANCE;
public BiFunction<Integer, Integer, Integer> A = (i, j) ->
i == 0 && j == 0 ? 0 :
i == 0 ? j :
j == 0 ? i :
this.A.apply(i - 1, j - 1) > this.A.apply(i - 1, j) ? this.A.apply(i - 1, j - 1) :
this.A.apply(i - 1, j);
public BiFunction<Integer, Integer, String> B = (i, j) ->
i == 0 || j == 0 ? null :
this.A.apply(i - 1, j - 1) > this.A.apply(i - 1, j) ? "D" :
"T";
}
这些函数背后的想法是它们模仿嵌套循环中的if / else if / else逻辑.
注1:A是递归lambda,而B使用A来获得结果.
注2:我还将if / else if / else语句更改为嵌套的三元运算符.
注3:函数是单例枚举,如Joshua Bloch所建议(见this answer).
注4:为避免自动装箱,应将IntBinaryOperator用于功能A.
注5:由于A是递归的,它应该使用automatic memoization来避免在给定相同的参数值时重新计算结果.
注6:由于B使用A来计算其结果,因此它还应使用A的记忆版本.
现在,您可以使用上面的函数来生成矩阵:
Integer[][] A = IntStream.range(0, n)
.mapToObj(i -> IntStream.range(0, m)
.mapToObj(j -> Functions.INSTANCE.A.apply(i, j))
.toArray(Integer[]::new))
.toArray(Integer[][]::new);
String[][] B = IntStream.range(0, n)
.mapToObj(i -> IntStream.range(0, m)
.mapToObj(j -> Functions.INSTANCE.B.apply(i, j))
.toArray(String[]::new))
.toArray(String[][]::new);
最后评论:这是我为满足自己的好奇心并深入研究函数式编程的奥秘所做的练习:)请不要在生产中使用此代码.