簡體   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

我有一個對象列表,其中一些可能與基於某個領域的其他對象相似。 在這種情況下,我想根據另一個字段的值過濾一個。

這是我進來的一個例子:

[
    {
        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.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);

我指定了一個LinkedHashMap作為中間存儲,以便任何其他員工(如 Dennis)將保留在他們的相對位置,如果這很重要的話。 如果沒有,您可以只使用toMap的 3 參數重載並將其關閉。

注意:這假設如果給定員工有多個條目,其中一個總是具有“電話”設備。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM