我问过this关于对1D列表做同样事情的问题,认为将答案应用到2D列表很容易,但事实并非如此。
根据Holger's回答我的代码,我提出了这个解决方案:
//list is of type ArrayList<List<Integer>>
list.stream()
.map(l -> Stream.concat(
l.subList(0, l.size() - 1).stream().map(i -> i - 2),
Stream.of(l.get(l.size() - 1)).collect(Collectors.toList())
))
.collect(Collectors.toList());
但是,当我尝试这个时,我得到了编译时错误Cannot infer type argument(s) for <R> map(Function<? super T,? extends R>)
。
如何在2D列表上执行此功能?
一些输入和输出示例:
[[1, 2, 3, 4], [5, 6, 7, 8]]
应输出[[-1, 0, 1, 4], [3, 4, 5, 8]]
答案 0 :(得分:2)
您的括号有问题。改变这个:
list.stream()
.map(l -> Stream.concat(
l.subList(0, l.size() - 1).stream().map(i -> i - 2),
Stream.of(l.get(l.size() - 1)).collect(Collectors.toList())
))
.collect(Collectors.toList());
对此:
list.stream()
.map(l -> Stream.concat(
l.subList(0, l.size() - 1).stream().map(i -> i - 2),
Stream.of(l.get(l.size() - 1))).collect(Collectors.toList())
)
.collect(Collectors.toList());
缩进在这里很重要,可以提高代码的可读性。我会重新说明第二个片段如下:
list.stream()
.map(l -> Stream.concat(
l.subList(0, l.size() - 1).stream().map(i -> i - 2),
Stream.of(l.get(l.size() - 1)))
.collect(Collectors.toList()))
.collect(Collectors.toList());
或者甚至更好,我会将修改内部列表的逻辑移动到辅助方法:
public final class Utility {
private Utility() { }
public static List<Integer> modifyAllButLast(List<Integer> list) {
return Stream.concat(
l.subList(0, l.size() - 1).stream().map(i -> i - 2),
Stream.of(l.get(l.size() - 1)))
.collect(Collectors.toList());
}
}
然后我会从外部流中使用这个方法:
list.stream()
.map(Utility::modifyAllButLast)
.collect(Collectors.toList());
注意:不需要将辅助方法移动到新的Utility
类,甚至可以让它成为非静态方法。在这种情况下,只需相应地更改Utility::modifyAllButLast
方法引用。
答案 1 :(得分:2)
Stream#concat将两个流汇总在一起,但你连续一个是List<Integer>
而不是Stream<Integer>
。
list.stream().map(l -> Stream.concat(
l.subList(0, l.size() - 1).stream().map(i -> i - 2),
Stream.of(l.get(l.size() - 1)).collect(Collectors.toList())
// it returns List<Integer> ---^
)).collect(Collectors.toList());
那么我们可以通过返回Stream
来修复错误,如下所示:
list.stream().map(l -> Stream.concat(
l.subList(0, l.size() - 1).stream().map(i -> i - 2),
Stream.of(l.get(l.size() - 1))
)).collect(Collectors.toList());
但是结果与预期不符。我们预计会返回List<List<Integer>>
,但会返回List<Stream<Integer>>
。我们可以将汇总的流收集到List<Integer>
,如下所示:
list.stream().map(main ->
Stream.concat(
main.subList(0, main.size() - 1).stream().map(i -> i - 2),
Stream.of(main.get(main.size() - 1))
).collect(Collectors.toList())
// ^--- collecting Stream<Integer> to List<Integer>
).collect(Collectors.toList());
但是我认为在这种情况下最好的方法是使用我在List#replaceAll中回答的another question更多表现力和<强>更快,因为Stream
比Collector
更重。
list.stream().map(main ->
main.stream().collect(collectingAndThen(toList(), it -> {
// v--- replacing all items in list except the last one
it.subList(0, it.size() - 1).replaceAll(item -> item - 2);
return it;
}))
).collect(Collectors.toList());
答案 2 :(得分:0)
这可能不是连接两个列表的最优雅方式,但它会这样做。
list.stream()
.map(integerList -> {
List<Integer> toReturn = integerList
.subList(0, integerList.size() - 1)
.stream()
.map(i -> i - 2)
.collect(Collectors.toList());
toReturn.add(integerList.get(integerList.size() - 1));
return toReturn;
})
.collect(Collectors.toList());