简体   繁体   English

如何过滤复杂对象列表,以便如果两个对象具有某个字段的值,我会根据条件删除一个

[英]How can I filter a List of complex objects so that if two have value for a field, I remove one based on criteria

I have a List of objects, some of which may be similar to others based on a certain field.我有一个对象列表,其中一些可能与基于某个领域的其他对象相似。 In this case, I want to filter one based on the value of another field.在这种情况下,我想根据另一个字段的值过滤一个。

Here is an example of what I have coming in:这是我进来的一个例子:

[
    {
        employeeId: 1230,
        firstName: "Ronald",
        lastName: "McDonald",
        device: "Laptop"
    },
    {
        employeeId: 2345,
        firstName: "Dennis",
        lastName: "Reynolds",
        device: "Laptop"
    },
    {
        employeeId: 1230,
        firstName: "Ronald",
        lastName: "McDonald",
        device: "Phone"
    }
]

I have 2 objects for Ronald McDonald (employee 1230).我有 2 个对象给 Ronald McDonald(员工 1230)。 I want the Laptop for all employees unless they have a Phone, in which case I just want the phone.我想要所有员工都使用笔记本电脑,除非他们有电话,在这种情况下,我只想要电话。 So I want to filter out the Ronald McDonald object with device= "Laptop" so that my output is as follows:所以我想用device= "Laptop"过滤掉 Ronald McDonald 对象,这样我的输出如下:

[
    {
        employeeId: 1230,
        firstName: "Ronald",
        lastName: "McDonald",
        device: "Phone"
    },
    {
        employeeId: 2345,
        firstName: "Dennis",
        lastName: "Reynolds",
        device: "Laptop"
    }
]

Filtering is easy enough, but for whatever reason I can't wrap my head around removing duplicates based on a condition.过滤很容易,但无论出于何种原因,我都无法根据条件删除重复项。

Does any helpful soul have a solution to my situation?是否有任何有用的灵魂可以解决我的情况?

I'm using Java 11, so I have access to Lambda functions, streams, all that good stuff.我使用的是 Java 11,所以我可以访问 Lambda 函数、流以及所有这些好东西。

Edit: My first crack at it is going terribly.编辑:我对它的第一次破解非常糟糕。 I feel like I'm grouping ok, but I can't seem to filter within that group:我觉得我分组没问题,但我似乎无法在该组内进行过滤:

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;
      }
}))));

Iterate through all the employees, and if the device is Phone search the list for the employee and add to the list entriesToRemove if another entry exists with that employee and the device is Laptop :遍历所有员工,如果设备是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()));
         }
    }
                
  

Finally remove the entries from the list with removeAll :最后使用removeAll从列表中删除条目:

list.removeAll(entriesToRemove);
System.out.printf(list.toString());

Edit : Solution using Stream API:编辑:使用 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());

Output:输出:

[Employee{employeeId=2345, device='Laptop'}, Employee{employeeId=1230, device='Phone'}]

You can use the mergeFunction of Collectors.toMap to choose the one with "Phone" as the device when there's more than one:当有多个设备时,您可以使用Collectors.toMapmergeFunction选择带有“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);

I specified a LinkedHashMap as the intermediate storage so that any other employees (like Dennis) will remain in their relative positions, if that's important.我指定了一个LinkedHashMap作为中间存储,以便任何其他员工(如 Dennis)将保留在他们的相对位置,如果这很重要的话。 If not, you can just use the 3 parameter overload of toMap and leave that off.如果没有,您可以只使用toMap的 3 参数重载并将其关闭。

Note: this assumes that if there is more than one entry for a given employee, one of them always has a device of "Phone".注意:这假设如果给定员工有多个条目,其中一个总是具有“电话”设备。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用流根据Map字段的条件过滤一组对象? - How do I filter using streams a set of objects based on criteria for a Map field? 如何根据某些条件过滤掉枚举列表? - How do I filter out a list of enums based on some criteria? 如何在一次迭代中按两个属性对对象列表进行分组? - How can I group a list of objects by two attributes in one iteration? 如何根据两个对象参数对对象的链接列表进行排序? - How can I sort a linked list of objects based on two of the objects parameters? 在列表中<Object> ,如何保留最近的条目并删除具有相同字段的先前条目? - In a List<Object>, how can I keep the most recent entry and remove previous entries which have an identical field? 使用 Java Streams,我可以根据与具有相同变量的辅助对象列表共享的变量过滤对象列表吗? - With Java Streams, can I filter a list of objects based on a variable that is shared with a secondary list of objects with that same variable? 如何将一个列表中具有相同值的两个字段的对象合并为一个简化列表? - How can I combine objects with two fields having the same values in a list into one reduced list? 我有一个连续包含超过1个值的列表视图,当我在Edittext中键入内容时,如何用名称值过滤列表? - I have a listview which contains more that 1 value in a row, how can i filter the list with a name value when i type in Edittext? 如何根据列表副本中的位置从列表中删除值? - How can I remove value from a list based off it's location from a copy of that list? 如何根据列表属性过滤 Java 列表 - How can I filter a Java List based on a list attribute
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM