在包含Streams的2D列表的修改列表中包含未修改列表中的元素

我问这个问题是关于对1D列表做同样的事情,认为将答案应用于2D列表会很容易,但事实并非如此。

基于Holger的答案我的代码,我提出了这个解决方案:

//list is of type ArrayList<List> 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 map(Function) ,但是,当我尝试这个时。

如何在2D列表上执行此function?

一些示例输入和输出:

[[1, 2, 3, 4], [5, 6, 7, 8]]应输出[[-1, 0, 1, 4], [3, 4, 5, 8]]

你的括号有问题。 改变这个:

 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 modifyAllButLast(List 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方法引用。

让我们一步一步修复错误

Stream#concat将两个流连接在一起,但是你连接一个是List而不是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()) // it returns List ---^ )).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> 。 我们可以将连接的流收集到List ,如下所示:

 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 to List ).collect(Collectors.toList()); 

我认为在这种情况下最好的方法是使用List#replaceAll ,我已经在你的另一个问题中回答了这个问题 ,因为StreamCollector更重,所以更具表现力更快

 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()); 

这可能不是连接两个列表的最优雅方式,但它会做到这一点。

 list.stream() .map(integerList -> { List 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());