java stream order by,如何在Java Stream中获取每种类型(按属性选择)的第一个对象(按功能排序)...

Imagine a simple object with 3 attributes:

public class Obj {

boolean toBeAdded;

String type;

int order;

public Obj(boolean toBeAdded, String type, int order) {

this.toBeAdded = toBeAdded;

this.type = type;

this.order = order;

}

public boolean isToBeAdded() {

return toBeAdded;

}

public String getType() {

return type;

}

public int getOrder() {

return order;

}

}

Imagine I have a List of several Objs, with different types:

import java.util.Arrays;

import java.util.List;

public class Utils {

static List createA(){

List list = Arrays.asList(

new Obj(true, "A", 1),

new Obj(false, "A", 2),

new Obj(true, "A", 3),

new Obj(false, "A", 4)

);

return list;

}

static List createB(){

List list = Arrays.asList(

new Obj(true, "B", 1),

new Obj(false, "B", 2),

new Obj(true, "B", 3),

new Obj(false, "B", 4)

);

return list;

}

static List createC(){

List list = Arrays.asList(

new Obj(false, "C", 1),

new Obj(false, "C", 2),

new Obj(true, "C", 3),

new Obj(true, "C", 4)

);

return list;

}

}

I want to somehow filter this list and have the latest Obj (highest order value) for each type that can be added (toBeAdded = true).

For this example, the result should be a list with:

Obj1: type 1, order 3

Obj2: type 2, order 3

Obj3: type 3, order 4

I know how to filter and how to sort, but I still couldn't understand how to get the first in each subtype. Is this against Stream rules? Since what I want to do is basically parse N different substreams, for N different types?

Here is what I could do so far:

import java.util.ArrayList;

import java.util.Comparator;

import java.util.List;

import java.util.stream.Collectors;

public class MainTest {

public static void main(String[] args) {

List list = new ArrayList<>();

list.addAll(Utils.createA());

list.addAll(Utils.createB());

list.addAll(Utils.createC());

System.out.println(list);

List filteredList = list

.stream()

.filter(Obj::isToBeAdded)

.sorted(Comparator.comparingInt(Obj::getOrder).reversed())

.collect(Collectors.toList());

System.out.println(filteredList);

}

}

However, this is only doing the easy part - filtering and ordering. I still need to do something like findFirst() for each type. Is there any way to do this?

Do I have to do 3 different streams (one for each type) and then merge the lists? Is there a way to do this without knowing how many types we will have?

I also read about collect(Collectors.groupingBy()) but this would create different maps for each type, which I don't want.

解决方案

Using groupingBy can help here along with a downstream of minBy/maxBy. This would provide a map to look up if the value after filtering is present per type.

Map> groupMaxOrderByType = list.stream()

.filter(Obj::isToBeAdded)

.collect(Collectors.groupingBy(Obj::getType,

Collectors.maxBy(Comparator.comparingInt(Obj::getOrder)))); //highest order

The lookup or access to these objects would transform into something like:

Obj maxPerTypeA = groupMaxOrderByType.get("A").orElse.. // similar for each type

Edit: Or if you were to collect all such present types into a final result, you could follow to access the values of the Map.

List result = groupMaxOrderByType.values().stream()

.filter(Optional::isPresent)

.map(Optional::get)

.collect(Collectors.toList());

Edit: Or to get rid of dealing with the Optional, you can use toMap with BinaryOperator.maxBy as a merge function.

Map groupMaxOrderByType = list.stream()

.filter(Obj::isToBeAdded)

.collect(Collectors.toMap(Obj::getType, Function.identity(),

BinaryOperator.maxBy(Comparator.comparingInt(Obj::getOrder))));

List result = new ArrayList<>(groupMaxOrderByType.values());

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值