![](/img/trans.png)
[英]How do I filter using streams a set of objects based on criteria for a Map field?
[英]How can I filter a List of complex objects so that if two have value for a field, I remove one based on criteria
我有一个对象列表,其中一些可能与基于某个领域的其他对象相似。 在这种情况下,我想根据另一个字段的值过滤一个。
这是我进来的一个例子:
[
{
employeeId: 1230,
firstName: "Ronald",
lastName: "McDonald",
device: "Laptop"
},
{
employeeId: 2345,
firstName: "Dennis",
lastName: "Reynolds",
device: "Laptop"
},
{
employeeId: 1230,
firstName: "Ronald",
lastName: "McDonald",
device: "Phone"
}
]
我有 2 个对象给 Ronald McDonald(员工 1230)。 我想要所有员工都使用笔记本电脑,除非他们有电话,在这种情况下,我只想要电话。 所以我想用device= "Laptop"
过滤掉 Ronald McDonald 对象,这样我的输出如下:
[
{
employeeId: 1230,
firstName: "Ronald",
lastName: "McDonald",
device: "Phone"
},
{
employeeId: 2345,
firstName: "Dennis",
lastName: "Reynolds",
device: "Laptop"
}
]
过滤很容易,但无论出于何种原因,我都无法根据条件删除重复项。
是否有任何有用的灵魂可以解决我的情况?
我使用的是 Java 11,所以我可以访问 Lambda 函数、流以及所有这些好东西。
编辑:我对它的第一次破解非常糟糕。 我觉得我分组没问题,但我似乎无法在该组内进行过滤:
List<Employee> reducedEmpList = empList.stream()
.collect(Collectors.groupingBy(Employee::getEmployeeId,
// Obviously this is not right:
Collectors.maxBy(Comparator.comparing(Employee::getDevice, (e1, e2) -> {
// Clearly this is not how a comparator works
if("Laptop".equalsIgnoreCase(e1.getDevice()){
return e2;
}
}))));
遍历所有员工,如果设备是Phone
搜索员工列表,如果该员工存在另一个条目并且设备是Laptop
,则将其添加到列表entriesToRemove
:
List<Employee> entriesToRemove = new ArrayList<>();
for(Employee employee : list){
if(employee.getDevice().equals("Phone")){
entriesToRemove.addAll(list.stream().filter(e ->
e.getEmployeeId() == employee.getEmployeeId() && e.getDevice().equals("Laptop"))
.collect(Collectors.toList()));
}
}
最后使用removeAll
从列表中删除条目:
list.removeAll(entriesToRemove);
System.out.printf(list.toString());
编辑:使用 Stream API 的解决方案:
List<Employee> reducedEmpList = list.stream()
.collect(Collectors.groupingBy(Employee::getEmployeeId,
Collectors.collectingAndThen(toList(), listPerEmployee ->
listPerEmployee.stream().filter(e -> e.getDevice().equals("Phone")).findFirst()
.map(Collections::singletonList).orElse(listPerEmployee))))
.values().stream().flatMap(Collection::stream).collect(toList());
输出:
[Employee{employeeId=2345, device='Laptop'}, Employee{employeeId=1230, device='Phone'}]
当有多个设备时,您可以使用Collectors.toMap
的mergeFunction
选择带有“Phone”的设备:
Collection<Employee> filtered = employees.stream().collect(Collectors
.toMap(e -> e.getEmployeeId(), e -> e,
(a, b) -> "Phone".equals(a.getDevice())? a : b,
LinkedHashMap::new)).values();
employees = new ArrayList<>(filtered);
我指定了一个LinkedHashMap
作为中间存储,以便任何其他员工(如 Dennis)将保留在他们的相对位置,如果这很重要的话。 如果没有,您可以只使用toMap
的 3 参数重载并将其关闭。
注意:这假设如果给定员工有多个条目,其中一个总是具有“电话”设备。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.