簡體   English   中英

只有當其他列表有元素時,才用 Java8 過濾一個列表

[英]Filter a List with Java8 only when other List has elements

我正在嘗試編寫代碼來過濾列表中的元素(如果它們存在於另一個列表中)。

如果第二個列表為空,業務邏輯要求我返回第一個列表中的所有元素。

List<String> list1 = Arrays.asList("a","b","c","d");         
//List<String> list2 = Arrays.asList("a","d");       
List<String> list2 = Collections.emptyList();        

if (!list2.isEmpty()) {
  List<String> finalList = list1.stream()
      .map(x -> x)
      .filter(x -> list2.isEmpty() && list2.contains(x))
      .collect(toList());
  return finalList;
} else {
  return list1;
}

有更好的方法嗎? 優選地,在單個 lambda function 中。

首先,條件list2.isEmpty() && list2.contains(x)不正確,它永遠不會被評估為true 因為list2可以為空或包含特定的 object,但不能同時包含兩者。

操作filter()將只保留那些與謂詞匹配的元素,因此您的 stream 將始終生成一個空列表

由於前面的if語句消除了list2為空的可能性,因此我假設正確的過濾條件必須是list2.contains(x)

有更好的方法嗎? 最好在單個 lambda function。

您可以使用 Java 8 方法Collection.removeIf()實現這一點,該方法需要一個Predicate並將從源中刪除與給定謂詞匹配的每個元素。

您不需要list1中的初始值,您可以直接在其上調用removeIf() ,否則您需要制作一份防御性副本。

為了獲得更好的性能,您需要用Set包裝第二個列表,在這種情況下contains()檢查將在恆定時間內完成。

Set<String> set2 = new HashSet<>(list2);
list1.removeIf(x -> !set2.contains(x); // element will get removed if not present in the set
return list1;

或者您可以像這樣生成一個新列表:

Set<String> set2 = new HashSet<>(list2);
return list1.stream()
        .filter(set2::contains)        // element will be preserved if it's present in the set
        .collect(Collectors.toList()); // or `toList()` with Java 16+

您可以嘗試將第二個列表流式傳輸到一個集合中,以避免在您的過濾謂詞中每次 (O(n^2)) 遍歷整個列表。

public List<String> filterElementsPresentInBothLists(List<String> list1, List<String> list2) {
        assert list2 != null;
        return list2.stream()
                .collect(Collectors.collectingAndThen(Collectors.toSet(),
                        setView -> setView.isEmpty() ? list1 :
                                list1.stream().filter(setView::contains)
                                        .collect(Collectors.toList())));
    }

我看到映射也不是必需的,下面的映射可以滿足您的要求,

        List<String> list1 = Arrays.asList("a","b","c","d");
        //List<String> list2 = Arrays.asList("a","d");
        List<String> list2 = Collections.emptyList();
        List<String> finalList = list1.stream()
                                    .filter(list2::contains)
                                    .toList(); // Java 16+
        List<String> list = toList.isEmpty() ? list2 : finalList;

        System.out.println(list);

將第二個列表轉換為 HashMap 可以將查找的時間復雜度降低到 O(1),因此總體時間復雜度將為 list1.size() + list2.size()。

        Map<String, String> map = list2.stream()
                .collect(Collectors.toMap(Function.identity(), Function.identity()));

        list1.stream()
                .filter( x -> list2.isEmpty() || map.containsKey(x))
                .collect(Collectors.toList());

暫無
暫無

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

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