如何使用Java Streams在修改后的列表中包含未修改列表中的元素?

时间:2017-05-26 21:53:54

标签: java java-8 java-stream

我正在尝试对map执行List<Integer>操作:

list.stream().map(i -> i - 2).collect(Collectors.toList());

我希望它只是通过,而不是对列表的最后一个元素执行操作。当然,...Collectors.toList()).add(i)不起作用,因为i超出了范围。

例如,输入列表[1, 2, 3, 4]应输出[-1, 0, 1, 4]

10 个答案:

答案 0 :(得分:4)

"data.mat"

答案 1 :(得分:2)

您可以流式传输原始列表并限制流以排除最后一个元素,执行映射并收集到新的ArrayList,然后将原始列表的最后一个元素添加到新的最后一个位置,可变列表:

int size = list.size();

List<Integer> result = list.stream()
    .limit(size - 1)
    .map(i -> i - 2)
    .collect(Collectors.toCollection(() -> new ArrayList(size)));

result.add(list.get(size - 1));

另一种方法是进行映射并将原始列表的所有元素收集到新列表中,然后简单地将原始列表的最后一个元素设置在新列表的最后位置,覆盖前一个元素: / p>

int size = list.size();

List<Integer> result = list.stream()
    .map(i -> i - 2)
    .collect(Collectors.toCollection(() -> new ArrayList(size)));

result.set(size - 1, list.get(size - 1));

答案 2 :(得分:2)

您可以使用Stream#toList撰写Stream#collectingAndThen以复制List,然后使用List#replaceAll替换除最后一项之外的所有项目。

List<Integer> result = list.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;
}));

AND 您可以看到流api只是将原始List复制到由流创建的另一个List中,因此您的代码可以简化如下:

List<Integer> result = new ArrayList<>(list);
result.subList(0, result.size() - 1).replaceAll(item -> item - 2);
//^--- if you don't want to copy the list, you can just operates on list instead   

答案 3 :(得分:1)

您需要稍微更改一下您的解决方案并使用IntStream#range索引到列表中list.size()-1。然后只需将初始列表中的最后一个元素添加到新列表中。

List<Integer> list = Arrays.asList(1, 2, 3, 4);
List<Integer> resultSet = IntStream.range(0,list.size()-1)
                          .map(i -> list.get(i) - 2)
                          .boxed().collect(Collectors.toCollection(ArrayList::new));
resultSet.add(list.get(list.size()-1));

答案 4 :(得分:1)

试试这个。

List<Integer> list = Arrays.asList(1, 2, 3, 4);
int last = list.size() - 1;
List<Integer> result = IntStream.range(0, list.size())
    .mapToObj(i -> i < last ? list.get(i) - 2 : list.get(i))
    .collect(Collectors.toList());
System.out.println(result);

答案 5 :(得分:1)

如果您不想处理可变列表或可变数据结构,那么解决此任务的一种方法是

List<Integer> result = Stream.concat(
        list.subList(0, list.size()-1).stream().map(i -> i - 2),
        Stream.of(list.get(list.size()-1)))
    .collect(Collectors.toList());

答案 6 :(得分:0)

您必须手动执行此操作:

List<Integer> list = Arrays.asList(1, 2, 3, 4);
List<Integer> mapped = list.stream().map(i -> i - 2).collect(Collectors.toCollection(ArrayList::new));
// Do this only if not empty...
mapped.remove(mapped.size()-1);
mapped.add(list.get(list.size()-1));

答案 7 :(得分:0)

另一种可能更优雅的解决方案:

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
Integer last = list.remove(list.size() - 1);
list.replaceAll(i -> i - 2);
list.add(last);

答案 8 :(得分:0)

另一种变体,只是为了好玩:

List<Integer> list = Arrays.asList(1, 2, 3, 4);
final int[] count = {0};
List<Integer> collect2 = list.stream()
    .map(i -> (++count[0] < list.size()) ? i - 2 : i)
    .collect(Collectors.toCollection(ArrayList::new));

答案 9 :(得分:0)

https://github.com/aspnet/Mvc/issues/4988为此问题提供了提取API:

user: {
    region: this.userData.userRegion,
    name: this.userData[this.userData.userRegion].info.name
},