2013-06-03 68 views
6

開始之前,我認爲這個問題有一個非常簡單的答案,我只是忽略了。我認爲手邊的問題還有更多的眼光能夠很快指出我的問題。如何從兩個獨立的ArrayList中刪除重複的對象?

我有兩個ArrayLists,我想比較並從它們中刪除重複項。第一個ArrayList是舊信息的ArrayList,其中第二個ArrayList包含新信息。

像這樣

ArrayList<Person> contactList = new ArrayList(); 
contactList.add(new Person("Bob"); 
contactList.add(new Person("Jake"); 
contactList.add(new Person("Joe"); 
ontactList.add(new Person("Rob"); 

ArrayList<Person> updatedContactList = new ArrayList(); 
updatedContactList.add(new Person("Bob"); 
updatedContactList.add(new Person("Jake"); 
updatedContactList.add(new Person("Joe"); 
updatedContactList.add(new Person("Phil"); 

Person類是非常簡單的,只是在這個例子中

public class Person { 
    private String name; 

    public Person(String a_name) { 
     name = a_name; 
    } 

    public String getName() { 
     return name; 
    } 
} 

創建因此,使用上面的例子,我想刪除所有重複。如果可能的話,我試圖將它保留在兩個ArrayLists中,但如果必須的話,我願意對其中一個ArrayLists進行深層克隆。

所以我希望得到的ArrayList有在它下面的信息,一旦比較完成

這裏是代碼我已經把

for(int i = 0; i < contactList.size(); i++) { 
    for(int j = 0; j < updatedContactList.size(); j++) { 

     if(contactList.get(i).getName().equals(updatedContactList.get(j).getName())) { 
      //removed friends      
      contactList.remove(contactList.get(i)); 

      //new friends ---- only one at a time works 
      //updatedContactList.remove(updatedContactList.get(j)); 
     } 
    } 
} 

我只能在上面的循環中從一個ArrayLists中刪除一個Person,否則我會得到不正確的結果。

所以我的問題是,有沒有一種簡單的方法來從兩個ArrayLists中刪除重複的元素?如果是這樣,我該怎麼做。

我意識到我可能深入克隆更新的ArrayList,只是刪除那個對象,但我想知道是否有一種方法,而不必克隆它。

我也意識到我可以將所有元素填充到一個Set中,它會刪除重複項,但我想要將「刪除」和「新」Person對象分開。

+0

我假設個人名單不會有重複,是正確的? – arshajii

+0

@arshajii一旦完成比較,每個列表都不應包含兩者之間的重複。一個ArrayList將包含已刪除的Person,另一個ArrayList將只包含新的Person對象。 – WilliamShatner

+0

我的意思是說,在任何事情都完成之前,這兩個名單。例如,你不能在'contactList'中有兩個'Bob',對嗎? – arshajii

回答

6

什麼你真的不是名單,而是集:模型無論是舊的和新的聯繫作爲Set。爲您的Person課程實施equalshashCode以確保正確操作。

一旦你的,你就可以寫單行計算組的差異(這是你所需要的):

final Set<Person> contactsBackup = new HashSet<>(contacts); 
contacts.removeAll(updatedContacts); 
updatedContacts.removeAll(contactsBackup); 

注意,這需要做出一個更副本,但它不是深拷貝—只複製引用。這是一個非常輕量級的操作,你不應該擔心它的影響。

如果由於某種原因並不明顯,我,你真正需要的名單,同樣的代碼會爲他們工作,太(List還定義removeAll),但你將不得不忍受爲O(n )這個操作的複雜性需要列表。

+0

+1。 'List#removeAll(Collection)'的運行時間實際上取決於作爲參數傳遞的集合的類型。你的陳述對於'list.removeAll(otherList);'是真實的。以下是'O(n)':'列表。removeAll(hashset);' – jlordo

+0

@MarkoTopolnik這似乎是一個很好的簡單方法來做到這一點(就像jLordo的方法一樣),但是如果我想讓我的列表排序,會發生什麼?例如,當我將它們從xml中解析出來時,它們按字母順序排列。但是如果我以後決定讓他們按照他們中的一些不同信息排序,那麼一旦他們成爲集合,它會是一個問題嗎? – WilliamShatner

+0

@jlordo嗯,我沒有反對你的說法:)但是我在我的評論中發現了一個錯誤,所以我刪除了它。我無法逐字保留代碼。 –

3

覆蓋equals()並在PersonhashCode(),只是做:

Set<Person> temp = new HashSet<>(contactList); 
contactList.removeAll(updatedContactList); 
updatedContactList.removeAll(temp); 
temp.clear(); // not necessary if this code is in a method 
+1

你能詳細說一下嗎?我假設爲'equals()'我會做我以上所做的事情(糾正我,如果我錯了)。我從來沒有重寫'hashCode()'。我在重寫的'hashCode()'方法中會做什麼? – WilliamShatner

+1

你在使用eclipse嗎?如果是這樣,點擊'源 - >生成hashCode()和等於()' – jlordo

+0

Netbeans 7.1(jdk仍然在6) – WilliamShatner

1

在這種情況下,如果可能的話,使用Set而不是List(如果您使用Hibernate從數據庫中獲取數據,則使用此選項)。然後,您可以在人員類中覆蓋equals和hashcode方法,以便可以添加所需的比較,並可以取出重複項。可以使用LinkedHashSet,因爲隨着數據增長,列表可能會變慢。

0

這是一個行優雅的解決方案利用了Java 8的功能

public static final <T> void removeCommonEntries(Collection<T> a, Collection<T> b){ 
     b.removeIf(i -> a.remove(i)); 
} 

我把這個解決方案在您的自定義CollectionUtils

相關問題