2012-08-03 157 views
70

我有兩個列表,其中有不同的對象。檢查一個列表是否包含另一個列表中的元素

List<Object1> list1; 
List<Object2> list2; 

我要檢查,如果從列表1元素list2中存在,基於特定屬性(Object1和Object2的有(其中包括),一個共同屬性(Long型),命名爲attributeSame)。

現在,我不喜歡這樣寫道:

boolean found = false; 
for(Object1 object1 : list1){ 
    for(Object2 object2: list2){ 
     if(object1.getAttributeSame() == object2.getAttributeSame()){ 
      found = true; 
      //also do something 
     } 
    } 
    if(!found){ 
     //do something 
    } 
    found = false; 
} 

但我認爲這是一個更好更快的方式來做到這一點:) 有人能提出呢?

謝謝!

+0

首先,當您設置found = true;然後簡單地打破;或出來的循環 – Shubhansh 2012-08-03 13:10:42

+0

http://stackoverflow.com/questions/5187888/java-searching-within-a-list-of-objects。此外,爲了迅速搜索嘗試使用二進制搜索,並改變你的DS套件的情況... – Shubhansh 2012-08-03 13:13:14

+0

他們是否共享除了對象共同的父母? – Woot4Moo 2012-08-03 13:16:59

回答

143

這可以通過基本的JDK來完成,無需在一個行修改輸入列表

!Collections.disjoint(list1, list2); 
+0

這不會總是返回false,因爲它們都是2個不同的對象? – Venki 2014-02-19 15:02:13

+1

恩,不是嗎?不相交的測試是否在兩個集合之間沒有對象equals()。 – 2014-02-19 16:15:56

+10

此外,請注意,對於列表,這將是O(n * m);如果你願意在比較之前把'list1'複製到'Set'中,你將得到O(n)+ O(m),即O(n + m),代價是一些額外的RAM;這是在速度或內存之間進行選擇的問題。 – 2016-03-01 13:10:21

1

爲了讓它更快,您可以添加一箇中斷;這樣,如果發現被設置爲true,則循環將停止:

boolean found = false; 
for(Object1 object1 : list1){ 
    for(Object2 object2: list2){ 
     if(object1.getAttributeSame() == object2.getAttributeSame()){ 
      found = true; 
      //also do something 
      break; 
     } 
    } 
    if(!found){ 
     //do something 
    } 
    found = false; 
} 

如果你想在名單代替的地圖,作爲關鍵字attributeSame,你可以在一個地圖檢查值更快,如果有相應的在第二張地圖中的價值還是沒有。

+0

嗨,湯姆,謝謝你的注意!是的,我在打字時忘了「休息」。但我想也許有一些算法,或者我應該將這些列表更改爲其他集合。 – Ned 2012-08-03 13:13:33

+0

我做了一個編輯回覆你的評論 – Tom 2012-08-03 13:29:01

+0

沒有比O(n * m)更好的東西嗎? – Woot4Moo 2013-01-17 14:02:00

2

根據的JavaDoc爲.contains(Object obj):如果此列表包含指定的元素,

返回true。更多 正式返回true,當且僅當此列表包含至少一個 元素e使得(o == null?e == null:o.equals(e))。

所以,如果你重寫你的.equals()方法了給定的對象,你應該能夠做到:if(list1.contains(object2))...

如果元素將是唯一的(即具有不同的屬性),你可以重寫.equals().hashcode()並將所有內容存儲在HashSets中。這將允許您在常量時間內檢查是否包含另一個元素。

26

您可以使用Apache Commons CollectionUtils

if(CollectionUtils.containsAny(list1,list2)) { 
    // do whatever you want 
} else { 
    // do other thing 
} 

這假定你已經正確重載了equals功能爲您的自定義對象。

+0

死連線,隊友。 – alexander 2016-02-15 13:22:28

+7

已經4年了,我也明確地說出了包和功能。 – Woot4Moo 2016-02-15 18:53:08

+0

當只有一個jdk解決方案時,用於apache commons的Downvote – ohcibi 2017-01-23 17:30:46

2

更快的方式將需要額外的空間。

例如:

  1. 把所有項目都在一個列表到一個HashSet(你必須自己實現哈希函數使用object.getAttributeSame())

  2. 經過其他列表並檢查是否有任何項目在HashSet中。

這樣,每個對象被訪問最多一次。並且HashSet足夠快以檢查或插入O(1)中的任何對象。

8

一個方法Collection命名retainAll但有一些副作用reference

只保留此列表中包含的 指定集合(可選操作)的元素。換句話說,從列表中刪除 所有未包含在 指定集合中的元素。

如果此列表改變調用的結果

它像

boolean b = list1.retainAll(list2); 
0

你可以定義你持有的數據類型?這是大數據嗎?它是排序? 我認爲您需要根據數據考慮不同的效率方法。

例如,如果您的數據很大並且未排序,您可以嘗試通過索引一起迭代這兩個列表,並將每個列表屬性存儲在另一個列表助手中。 然後您可以通過幫助程序列表中的當前屬性進行交叉檢查。

祝你好運

編輯:我不會推薦重載等於。它的危險和可能違揹你的對象oop的含義。

2

Loius答案是正確的,我只想補充一個例子:

listOne.add("A"); 
listOne.add("B"); 
listOne.add("C"); 

listTwo.add("D"); 
listTwo.add("E"); 
listTwo.add("F");  

boolean noElementsInCommon = Collections.disjoint(listOne, listTwo); // true 
+0

我想如果你添加元素'A'到第二個列表listTwo.add(「A」);即使Collections.disjoint(listOne,listTwo);返回true。 – 2017-06-28 20:56:58

相關問題