如何获取Java流中每种类型(按属性选择)的第一个对象(带有任何按函数排序的对象)
想象一个具有3个属性的简单对象:如何获取Java流中每种类型(按属性选择)的第一个对象(带有任何按函数排序的对象),java,arrays,list,java-stream,grouping,Java,Arrays,List,Java Stream,Grouping,想象一个具有3个属性的简单对象: 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 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;
}
}
假设我有一个包含多个不同类型的Obj
s的列表:
import java.util.Arrays;
import java.util.List;
public class Utils {
static List<Obj> createA(){
List<Obj> 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<Obj> createB(){
List<Obj> 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<Obj> createC(){
List<Obj> 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;
}
}
然而,这只是做简单的部分过滤和排序。对于每个类型
,我仍然需要执行类似于findFirst()
的操作。有没有办法做到这一点
我需要做3个不同的流(每种类型一个)然后合并列表吗?有没有一种方法可以做到这一点,而不知道我们将有多少种类型?
我还阅读了有关
collector(Collectors.groupingBy())
的内容,但这会为每种类型创建不同的映射,这是我不想要的。使用groupingBy
以及minBy
/maxBy
的下游功能在这里会有所帮助。这将提供一个映射来查找每个类型是否存在筛选后的值
Map<String, Optional<Obj>> groupMaxOrderByType = list.stream()
.filter(Obj::isToBeAdded)
.collect(Collectors.groupingBy(Obj::getType,
Collectors.maxBy(Comparator.comparingInt(Obj::getOrder)))); //highest order
编辑:或者,如果要将所有此类当前类型收集到最终结果中,则可以按照以下步骤访问映射的值
List<Obj> result = groupMaxOrderByType.values().stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
这确实是朝着好的方向发展。这将创建一个包含3个条目的映射,每个条目只有一个条目,正如我最初询问的那样,这是最高的
order
值。但是有没有一种方法可以立即将其简化为列表?@pmendesm您可以访问映射的值。(stream
ing和filter
ing根据您的进一步要求)我可以这样做:List newList=newarraylist();groupMaxOrderByType.forEach((s,obj)->newList.add(obj.get())代码>我想知道这是否可以用更少的操作来实现。排序为:List filteredList=List.stream().filter(Obj::isToBeAdded)、substream(Obj::getType)、sorted(Comparator.comparingit(Obj::getOrder).reversed()).findFirst().collect(collector.toList())代码>被接受为答案在替换收集器.groupingBy(Obj::getType,Collectors.maxBy(Comparator.comparingit(Obj::getOrder))
时,您不需要处理可选的收集器.toMap(Obj::getType,Function.identity(),binarymoperator.maxBy(Comparator.comparingit(Obj::getOrder)))
Obj maxPerTypeA = groupMaxOrderByType.get("A").orElse.. // similar for each type
List<Obj> result = groupMaxOrderByType.values().stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
Map<String, Obj> groupMaxOrderByType = list.stream()
.filter(Obj::isToBeAdded)
.collect(Collectors.toMap(Obj::getType, Function.identity(),
BinaryOperator.maxBy(Comparator.comparingInt(Obj::getOrder))));
List<Obj> result = new ArrayList<>(groupMaxOrderByType.values());