2013-06-03 10 views
6

Przed rozpoczęciem, myślę, że to pytanie ma bardzo prostą odpowiedź, że właśnie przeoczyłem. Pomyślałem, że jeszcze kilka oczu na to pytanie będzie w stanie wskazać mój problem dość szybko.Jak usunąć zduplikowane obiekty z dwóch oddzielnych ArrayLists?

Mam dwa ArrayLists, które chcę porównać i usunąć duplikaty z każdego z nich. Pierwsza ArrayList jest starszą informacją o numerze ArrayList, gdzie jako druga ArrayList zawiera nową informację.

Podobnie jak

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"); 

Moja Person klasa jest bardzo proste, stworzone wyłącznie dla tego przykładu

public class Person { 
    private String name; 

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

    public String getName() { 
     return name; 
    } 
} 

Tak, stosując powyższe przykłady, chcę usunąć wszystkie duplikaty. Próbuję zachować to do dwóch ArrayLists, jeśli to możliwe, ale jestem gotów zrobić głęboki klon jednej z ArrayLists, jeśli muszę.

Więc chcę otrzymany ArrayList mieć następujące informacje w nim kiedyś porównanie odbywa

Oto kod I już ułożyła

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)); 
     } 
    } 
} 

jestem w stanie tylko aby usunąć osobę z jednego z ArrayLists w powyższej pętli w przeciwnym razie otrzymam niepoprawne wyniki.

Moje pytanie brzmi: czy istnieje prosty sposób na usunięcie zduplikowanych elementów z obu ArrayLists? Jeśli tak, jak mam to zrobić.

Zdaję sobie sprawę, że prawdopodobnie mógłbym gruntownie sklonować zaktualizowany ArrayList i po prostu usunąć obiekty z tego, ale zastanawiam się, czy istnieje sposób, bez konieczności klonowania go.

Zdaję sobie również sprawę, że mogłem po prostu zapakować wszystkie elementy do zestawu i usunąć duplikaty, ale chcę zachować oddzielne obiekty "usunięte" i "nowe".

+0

Zakładam, że poszczególne listy nie będą miały duplikatów, prawda? – arshajii

+0

@arshajii Po zakończeniu porównania, każda lista nie powinna zawierać żadnych duplikatów między tymi dwoma. Jedna ArrayList będzie zawierała usuniętą "osobę", a druga ArrayList będzie zawierała tylko nowe obiekty "Person". – WilliamShatner

+0

Mam na myśli wcześniej, zanim cokolwiek zostanie zrobione na dwóch listach. Nie możesz na przykład mieć dwóch "Boba" w 'liście kontaktów ', prawda? – arshajii

Odpowiedz

6

Co naprawdę masz nie jest list, ale zestawy: model zarówno stare i nowe kontakty jako Set. Zaimplementuj także equals i hashCode dla swojej klasy Person, aby zapewnić poprawne działanie.

Kiedy już, że będziesz w stanie napisać jednej wkładki do obliczania ustalonych różnic (co jest, co trzeba):

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

Należy pamiętać, że wiąże się to co jeszcze jedną kopię, ale nie jest głęboką kopią — tylko odniesienia są kopiowane. Jest to bardzo lekka operacja i nie powinieneś martwić się jej wpływem.

Jeśli z jakiegoś powodu w ogóle dla mnie oczywiste, naprawdę musisz list, ten sam kod będzie pracować dla nich zbyt (List definiuje również removeAll), ale będzie musiał żyć z O (n ) złożoność ta operacja pociąga za listy.

+0

+1. Środowisko wykonawcze 'List # removeAll (Collection)' faktycznie zależy od typu kolekcji przekazanej jako parametr. Twoje zdanie jest prawdziwe dla 'list.removeAll (otherList);'. Poniżej znajduje się 'O (n)': 'lista.removeAll (hashset); ' – jlordo

+0

@MarkoTopolnik Wydaje się to być całkiem prostym sposobem (podobnie jak metoda jLordo), ale co się stanie, jeśli chcę, aby moje listy były posortowane? Na przykład, gdy je parsuję z xml, są one alfabetycznie. Ale jeśli później zdecyduję, że chcę, aby były posortowane według różnych informacji, czy będzie to problem, gdy będą one ustawione? – WilliamShatner

+0

@jlordo Cóż, w ogóle nie sprzeciwiłem się twojemu oświadczeniu :) Ale zauważyłem błąd w moim komentarzu, więc usunąłem go. Nie mogłem zachować kodu w dosłownym brzmieniu. –

3

Zastąp equals() i hashCode() w swojej klasie Person i po prostu zrobić:

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

Czy możesz trochę rozwinąć? Zakładam, że dla 'equals()' zrobię to, co zrobiłem powyżej (popraw mnie jeśli się mylę). Nigdy wcześniej nie zastąpiłem 'hashCode()'. Co powinienem zrobić w mojej przesłoniętej metodzie 'hashCode()'? – WilliamShatner

+1

Czy używasz Zaćmienie? Jeśli tak, kliknij "Źródło -> Wygeneruj hashCode() i równe()" – jlordo

+0

Netbeans 7.1 (jdk jest wciąż na poziomie 6) – WilliamShatner

1

W tym przypadku należy użyć opcji Ustaw, a nie listy (ta opcja jest używana w przypadku pobierania danych z bazy danych przy użyciu opcji Hibernacja), o ile jest to możliwe. Następnie możesz przesłonić metodę equals i hashcode w klasie person, dzięki czemu można dodawać wymagane porównania, a duplikaty mogą być usuwane. LinkedHashSet może być używany jako lista może stać się wolna, ponieważ dane w niej rosną.

0

Jest to jedna linia eleganckie rozwiązanie zastosowanie w podejmowaniu Java 8 możliwości

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

kładę to rozwiązanie w swoim zwyczaju CollectionUtils.