[英]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.