2008-12-10 8 views
15

Ich habe ein Array von Objekten, die die Duplikate entfernt/gefiltert benötigen. Ich würde gleich & hachCode auf die Objektelemente überschreiben und sie dann in ein Set stecken ... aber ich dachte, ich sollte Stackoverflow abfragen, um zu sehen, ob es einen anderen Weg gab, vielleicht eine clevere Methode einer anderen API ?Was ist der beste Weg, um Duplikate in einem Array in Java zu entfernen?

+1

mit Warum sich an dieser Stelle setzen? Warum nicht die Duplikate an erster Stelle verhindern? – LeppyR64

+4

Stellen Sie eine Frage zum Entfernen von Duplikaten ... erhalten Sie eine Reihe von doppelten Antworten. Die Ironie! – erickson

+1

lol @ erickson, so wahr! – Brabster

Antwort

19

Ich würde mit Ihrem Ansatz zu übersteuern hashCode() und equals() und etwas verwenden, das Set implementiert.

Dies macht auch für alle anderen Entwickler absolut klar, dass das Nicht-Duplikat-Merkmal erforderlich ist.

Ein weiterer Grund - Sie erhalten eine Implementierung zu wählen, die Ihren Bedürfnissen am besten entspricht jetzt:

und Sie müssen nicht Ihre ändern Code, um die Implementierung in der Zukunft zu ändern.

0

Ein Set ist definitiv Ihre beste Wette. Die einzige Möglichkeit, Dinge aus einem Array zu entfernen (ohne ein neues zu erstellen), besteht darin, sie aus dem Array zu entfernen. Am Ende gibt es dann eine Menge Null-Checks.

3

Overriding equals und hashCode und das Erstellen eines Sets war mein erster Gedanke auch. Es empfiehlt sich, eine überarbeitete Version dieser Methoden in Ihrer Vererbungshierarchie zu verwenden.

Ich denke , dass, wenn Sie einen LinkedHashSet verwenden erhalten Sie sogar um einzigartige Elemente ...

+0

Ja, 'LinkedHashSet' wird den Anzeigenauftrag beibehalten. –

+0

Es ist nicht gut, equals und hashCode "anyway" zu überschreiben, besonders in jeder Klasse, die in einer Vererbungshierarchie sitzt. Weitere Informationen finden Sie unter Effektives Java (Bloch). – McDowell

+0

McDowell, ich wollte wirklich klar sein - ich meinte, dass es irgendwo in Ihrer Vererbungshierarchie eine überschriebene Version * geben sollte * und ich habe die Antwort geändert, um das widerzuspiegeln. Ich habe keine Kopie von Effektivem Java - ist es das, worum Bloch geht? –

8

ich dies im Web gefunden

Hier sind zwei Methoden, die Ihnen erlauben, um Duplikate zu entfernen in einer ArrayList. removeDuplicate verwaltet nicht die Reihenfolge, in der removeDuplicateWithOrder die Reihenfolge mit einem gewissen Leistungsaufwand aufrechterhält.

  1. Die removeDuplicate Methode:

    /** List order not maintained **/ 
    public static void removeDuplicate(ArrayList arlList) 
    { 
    HashSet h = new HashSet(arlList); 
    arlList.clear(); 
    arlList.addAll(h); 
    } 
    
  2. Die removeDuplicateWithOrder Methode:

    /** List order maintained **/ 
    public static void removeDuplicateWithOrder(ArrayList arlList) 
    { 
        Set set = new HashSet(); 
        List newList = new ArrayList(); 
        for (Iterator iter = arlList.iterator(); iter.hasNext();) { 
         Object element = iter.next(); 
         if (set.add(element)) 
         newList.add(element); 
        } 
        arlList.clear(); 
        arlList.addAll(newList); 
    } 
    
+0

Gute Antwort, aber Ihr 2. Beispiel ist nicht in einem Code-Format Block – TravisO

+0

dank Ken G ...Ich habe es ein paar Mal ausprobiert, aber ich konnte den zweiten Code-Blog nicht reparieren –

+1

LinkedHashSet hält es in Ordnung. Das kann es weiter optimieren. –

0

von einer allgemeinen Programmierstandard Sprechen können Sie immer doppelt so viele Sammlungen aufzuzählen die dann vergleichen die Quelle und Ziel.

Und wenn Ihre innere Aufzählung immer einen Eintrag nach der Quelle beginnt, ist es ziemlich effizient (Pseudo-Code zu folgen)

foreach (array as source) 
{ 
    // keep track where we are in the array 
    place++; 
    // loop the array starting at the entry AFTER the current one we are comparing to 
    for (i=place+1; i < max(array); i++) 
    { 
     if (source === array[place]) 
     { 
      destroy(array[i]); 
     } 
    } 
} 

Sie wohl eine Pause hinzufügen könnte; Aussage nach dem zerstören, aber dann entdecken Sie nur das erste Duplikat, aber wenn das alles ist, was Sie jemals haben werden, dann wäre es eine nette kleine Optimierung.

1

Ich möchte den Punkt von Jason in den Kommentaren wiederholen:

Warum setzen Sie sich zu diesem Zeitpunkt überhaupt?

Warum ein Array für eine Datenstruktur verwenden, die überhaupt keine Duplikate enthalten sollte?

Verwenden Sie eine Set oder eine SortedSet (wenn die Elemente auch eine natürliche Reihenfolge haben), um die Elemente zu halten. Wenn Sie den Anzeigenauftrag beibehalten müssen, können Sie die LinkedHashSet wie angegeben verwenden.

Einige Datenstrukturen nachzubearbeiten ist oft ein Hinweis darauf, dass Sie zu Beginn eine andere gewählt haben sollten.

+0

Ich stimme allen Kommentaren zu den Bedenken der ursprünglichen Datenstruktur, die ein Array ist, zu. Ich versuche, den Entwickler dazu zu bewegen, zu einem Set umzuformen. Vielen Dank für Ihr Feedback und Ihre Weisheit! – Liggy

1

Natürlich wirft der ursprüngliche Post die Frage auf: "Wie haben Sie das Array (das könnte doppelte Einträge enthalten) an erster Stelle?"

Benötigen Sie das Array (mit Duplikaten) für andere Zwecke, oder könnten Sie einfach ein Set von Anfang an verwenden?

Wenn Sie die Anzahl der Vorkommen jedes Werts wissen müssen, können Sie alternativ auch Map<CustomObject, Integer> verwenden, um die Anzahl zu überwachen. Außerdem kann die Google Collections Definition der Multimap-Klassen von Nutzen sein.

2

Grundsätzlich möchten Sie eine LinkedHashSet<T> Implementierung, die die List<T> Schnittstelle für den wahlfreien Zugriff unterstützt. Daher ist es das, was Sie brauchen:

public class LinkedHashSetList<T> extends LinkedHashSet<T> implements List<T> {

// Implementations for List<T> methods here ...

}

Die Umsetzung der List<T> Methoden würde die zugrunde liegenden LinkedHashSet<T> Zugriff und Manipulation. Der Trick besteht darin, dass sich diese Klasse korrekt verhält, wenn man versucht, Duplikate über die List<T> add -Methoden hinzuzufügen (eine Exception auszulösen oder das Item bei einem anderen Index wieder hinzuzufügen) wären Optionen: Sie können diese auswählen oder konfigurierbar machen der Klasse).

+0

Das schlage ich auch vor. –

1

eine Liste toRemove Verwenden Element beim ersten Mal iterator Stolpern hinein aufnehmen, danach, wenn Treffen wieder mit dem Element aufgezeichnet, entfernen Sie es iterator.remove()

 
private void removeDups(List list) { 
     List toRemove = new ArrayList(); 
     for(Iterator it = list.iterator(); it.hasNext();) { 
      Object next = it.next(); 
      if(!toRemove.contains(next)) { 
       toRemove.add(next); 
      } else { 
       it.remove(); 
      } 
     } 
     toremove.clear(); 
    }