Java8 Stream 流一边 filter 过滤一边 map 映射??

2020-11-20 16:10:38 +08:00
 easterfan

一时 stream 一时爽,用习惯了以后,突然想到对于流,能否实现过滤和 map 同时进行的操作,比如一个场景:

// 如果元素是奇数,就 + 1,如果元素是偶数,就 +2,期望一顿流式操作后,输出一个新的 List:{2,4,4,6,6}

List<Integer> input = Arrays.asList(1, 2, 3, 4, 5);

inputList.stream()
         .filter(p -> xxx)
         .map(p -> xxx)
         .collect(Collectors.toList());

现在最高频用到的 filter 通常只有一个条件,是从原来的 List 中过滤出满足条件的元素,然后对这些元素进行 map 操作,

如果对一个集合,有两种过滤条件 A 和 过滤条件 B,满足过滤条件 A 就对元素进行 mapA 操作,满足过滤条件 B,就对元素进行 mapB 操作,最后元素都按照不同的 map 方式映射完了,再放到同一个集合里~~

初用 stream,有大佬这样操作过嘛~~

2350 次点击
所在节点    问与答
14 条回复
chanchan
2020-11-20 16:27:22 +08:00
peek 了解一下
wowo243
2020-11-20 16:29:16 +08:00
partitioningBy()?
ye2moe
2020-11-20 16:33:19 +08:00
直接的话是做不到的,可以搞两个流操作再合起来就好了。
easterfan
2020-11-20 16:57:54 +08:00
@wowo243
@ye2moe
```java
Map<Boolean, List<Integer>> partitionMap = Stream.of(1, 2, 3, 4, 5).collect(Collectors.partitioningBy(p -> p / 2 == 0));

Stream<Integer> evenStream = partitionMap.get(true).stream().map(p -> p + 2);
Stream<Integer> oddStream = partitionMap.get(false).stream().map(p -> p + 1);
Stream.concat(evenStream, oddStream);
```
分组成两个流,然后再合并,合并后的流和原来的流元素顺序不一样了~~
anzu
2020-11-20 17:12:21 +08:00
为什么要 filter,奇偶不是二选一吗。如果判断条件复杂,要么 map 里面多写点代码,要么用 for
input.stream().map(p -> p % 2 == 0 ? p + 2 : p + 1).collect(Collectors.toList())
easterfan
2020-11-20 17:50:45 +08:00
@anzu
感谢大佬!解决了我的问题,用 map 前总是很习惯的 filter 一下,有了思维定式,用你的思路,把判断逻辑写在 map 里,对一个元素 map 前先做一次判断,然后执行对应的 map,已经达到了我在找的一边 filter,一边 map 的想法,感谢!

```java
Stream.of(1,2,3,4,5)
.map(p -> {if(isFilterA) mapA(); if (isFilterB) mapB(); if (isFilterC) mapC();})
.collect(Collectors.toList());
```
(原来的固定思维的想法~:)
https://imgur.com/7sn8euR
jimmyismagic
2020-11-20 17:57:28 +08:00
@easterfan filter 概念要搞清楚啊,没事干嘛搞 filter
optional
2020-11-20 18:00:34 +08:00
rx 欢迎你
easterfan
2020-11-20 18:05:06 +08:00
@jimmyismagic 母鸡啊~写顺手了,map 前必 filter~~Q
easterfan
2020-11-20 19:02:42 +08:00
@optional
敢问 rx 是?这 id 很 6
jimmyismagic
2020-11-20 21:10:35 +08:00
@easterfan rxJava,另外还有 project reactor,都是响应式编程,但其中也使用了 streams 里的一些概念
oneisall8955
2020-11-20 22:35:05 +08:00
在 map 里面直接判断 A 或 B 条件分开转换就行了吧

借楼,题外话,最近密的 stream 的另一个 API,Collectors.mapping,真是节省了不少代码逻辑,主要用于 group 分组后的 value 集合再 map

https://stackoverflow.com/questions/52281724/java-streams-group-list-entries-based-on-a-property-but-collect-a-property-of-ob

知道这个 API 的大佬请忽略
zch693922
2020-11-21 09:42:05 +08:00
按一楼的 peek 一下就可以了
list.stream().peek(item -> {
if (xxxxx) { do something}
if (xxxx) {item.setXXX}
})
easterfan
2020-12-08 14:43:30 +08:00
@zch693922
@chanchan

感谢回答!最近试了 map 和 peek 两种实现方式,实践后发现可能 map 更适用这种情况,具体原因是使用 peek 后续再进行终端操作(比如 collect/count )时,会出现报错:`java.lang.UnsupportedOperationException`, peek 可能只适合调试的场景,个人解释能力有限,感兴趣的话这篇文章举的例子挺好的:

https://stackoverflow.com/questions/44370676/java-8-peek-vs-map

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/727591

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX