java8 stream 分组_JAVA8用stream解决分组的问题

GroupBy是个Collector,它是用来进行Stream上的collect操作的。Collect是一个Mutable Reduction。

所谓reduction,相当于把集合里的每一个元素依次带入一个函数,最终得到一个值。

比如求一组int的和,可以用reduction写作。

int sum = numbers.stream().reduce(0, (sum,n) -> sum+n);

其中0是初始和,函数(sum,n)->sum+n 对每个整数调用,最终得到所有数的和。

而所谓Mutable Reduction。是指最终产生的值是个可变的对象,比如list。

回到GroupBy, 它会根据条件把数据产生为Map>的形式。

所以如果用GroupBy做到你想要达到的效果,可以这样写:

List users = Arrays.asList(newUser(20), newUser(35), newUser(20));

List groupedUsers = users.stream()

.collect(Collectors.groupingBy(User::getAge)) //Map {20: [user{count:1, age:20}, user{count:1, age:20}]}, {35: [user{count:1, age:35}]

.entrySet() //Map变为entry列表,方便继续Stream操作

.stream().map(

(entry) -> new User(entry.getValue().size(), entry.getKey()))

//根据Entry产生新的User,list的长度是新的Count,key值是age

.sorted(Comparator.comparingInt(User::getAge)) //排序是为了方便后面验证结果

.collect(Collectors.toList()); //从Stream变回list

assertEquals(2, groupedUsers.size());

assertEquals(20, groupedUsers.get(0).getAge());

assertEquals(2, groupedUsers.get(0).getCount());

assertEquals(35, groupedUsers.get(1).getAge());

assertEquals(1, groupedUsers.get(1).getCount());

当然也可以直接写collect的逻辑,不使用GroupBy产生的Map。

List groupedUsers = users.stream().collect(

ArrayList::new, //初始的list

(list, user)-> { //对每个User调用的函数

Optional ageAdded = list.stream()

.filter(u1 -> u1.getAge() == user.getAge())

.findAny(); //查找是否已经加入list了

if ( ageAdded.isPresent() ) { //如果这个age已经在list了,修改user的count值

User counted = ageAdded.get();

counted.setCount(counted.getCount()+1);

} else { //加入新的user

list.add(new User(user.getCount(), user.getAge()));

}

},

ArrayList::addAll //合并各小段user list的函数,不并行处理Stream的话不会用到

);

可以看到因为要找list里已经加入的user,所以这样写也并不简单,而且可能比map更加低效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值