2017-05-26 60 views
2

我試圖做一個List<Integer>一個map操作:如何使用Java Streams將未修改列表中的元素包含在修改列表中?

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

而是執行列表的最後一個元素上操作的,我想它只是通過。 ...Collectors.toList()).add(i)不起作用,當然,因爲i超出了範圍。

例如,輸入列表[1, 2, 3, 4]應該輸出[-1, 0, 1, 4]

+3

提取子列表直到大小-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)); 

另一種方式是進行映射,收集原始列表的所有元素在新的列表,然後簡單地設置在新的列表的最後位置的原始列表的最後一個元素,並覆蓋前一個元素:

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)); 
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)); 
+2

'toList()':「*有沒有保證的類型,可變性,可串行化,或線程安全的列表返回*」 – steffen

+0

@steffen我想我沒有太注意,但我已經更新我的帖子以適應您的評論。 –

+1

一個更好的解決方案是流和映射一個子列表。這將在大型鏈表上產生糟糕的表現。 –

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)); 
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); 
4
List<Integer> result = 
    list.subList(0, list.size() - 1) 
     .stream().map(i -> i - 2) 
     .collect(Collectors.toCollection(ArrayList::new)); 
result.add(list.get(list.size() - 1)); 
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); 
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)); 
2

您可以撰寫Stream#toListStream#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; 
})); 

你可以看到流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 
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()); 
0

StreamEx提供了提取API爲這樣一個問題:

StreamEx.of(1, 2, 3, 4).mapLastOrElse(i -> i - 2, Function.identity()).toList();