如何查找兩個列表之間的差異?
1. 概述
查找相同數據類型的對象集合之間的差異是一項常見的編程任務。舉個例子,假設我們有一份申請考試的學生名單和另一份通過考試的學生名單。這兩張名單的區別會告訴我們那些沒有通過考試的學生。
在Java中,List API 中沒有顯式的方法來查找兩個列表之間的差異,盡管有一些helper方法非常接近。
在本篇文章中,我們將了解如何找出兩個列表之間的差異。我們將嘗試幾種不同的方法,包括普通的Java(有和沒有Streams),以及使用第三方庫,如Guava和Apache Commons Collections。
2. 測試設置
首先定義兩個列表,我們將用它們來測試示例:
- public class FindDifferencesBetweenListsUnitTest {
- private static final List listOne = Arrays.asList("Jack", "Tom", "Sam", "John", "James", "Jack");
- private static final List listTwo = Arrays.asList("Jack", "Daniel", "Sam", "Alan", "James", "George");
- }
3. 使用 Java List API
我們可以創建一個列表的副本,然后使用List 的方法removeAll() ,刪除與另一個相同的所有元素:
- List<String> differences = new ArrayList<>(listOne);
- differences.removeAll(listTwo);
- assertEquals(2, differences.size());
- assertThat(differences).containsExactly("Tom", "John");
讓我們把這個顛倒過來,從另一個角度找出差異:
- List<String> differences = new ArrayList<>(listTwo);
- differences.removeAll(listOne);
- assertEquals(3, differences.size());
- assertThat(differences).containsExactly("Daniel", "Alan", "George");
我們還應該注意到,如果我們想找到兩個列表之間的公共元素,List 還有一個 retainal 方法。
4. 使用 Streams API
Java Stream API 可用于對集合中的數據執行順序操作,包括過濾列表之間的差異:
- List<String> differences = listOne.stream()
- .filter(element -> !listTwo.contains(element))
- .collect(Collectors.toList());
- assertEquals(2, differences.size());
- assertThat(differences).containsExactly("Tom", "John");
與第一個示例一樣,我們可以切換列表的順序,以從第二個列表中找到不同的元素:
- List<String> differences = listTwo.stream()
- .filter(element -> !listOne.contains(element))
- .collect(Collectors.toList());
- assertEquals(3, differences.size());
- assertThat(differences).containsExactly("Daniel", "Alan", "George");
注意 List.contains() 對于較大的列表來說,可能是一項成本高昂的操作。
5. 使用第三方庫
5.1. 使用Google Guava
Guava 包含 Sets.difference 方法, 但要使用它,我們需要先將列表轉換為集合:
- List<String> differences = new ArrayList<>(Sets.difference(Sets.newHashSet(listOne), Sets.newHashSet(listTwo)));
- assertEquals(2, differences.size());
- assertThat(differences).containsExactlyInAnyOrder("Tom", "John");
注意,將 列表 轉換為 集合 會產生重復數據消除和重新排序的效果。
5.2. 使用 Apache Commons Collections
Apache Commons Collections中的 CollectionUtils 包含 removeAll 方法.
該方法類似于List.removeAll(),同時也為結果創建一個新的集合:
- List<String> differences = new ArrayList<>((CollectionUtils.removeAll(listOne, listTwo)));
- assertEquals(2, differences.size());
- assertThat(differences).containsExactly("Tom", "John");
6. 處理重復值
現在讓我們看看當兩個列表包含重復值時的差異。
為了實現這一點,我們需要從第一個列表中刪除重復的元素,精確到它們包含在第二個列表中的次數
在我們的示例中,“Jack”值在第一個列表中出現兩次,在第二個列表中僅出現一次:
- List<String> differences = new ArrayList<>(listOne);
- listTwo.forEach(differences::remove);
- assertThat(differences).containsExactly("Tom", "John", "Jack");
我們也可以使用Apache Commons Collections中的subtract方法來實現:
- List<String> differences = new ArrayList<>(CollectionUtils.subtract(listOne, listTwo));
- assertEquals(3, differences.size());
- assertThat(differences).containsExactly("Tom", "John", "Jack");
7. 結論
在本文中,我們探討了幾種查找列表之間差異的方法。
在這些示例中,我們介紹了一個基本的Java解決方案,一個使用StreamsAPI的解決方案,以及Google Guava和Apache Commons Collections等第三方庫,以及了解了如何處理重復值。
本文轉載自微信公眾號「鍋外的大佬」,可以通過以下二維碼關注。轉載本文請聯系鍋外的大佬公眾號。