Doppelte Datensätze aus ArrayList entfernen

Hallo,

ich habe eine kleines Problem… Habe eine CSV-Datei mit mehreren doppelten Datensätzen.
Diese habe ich jetzt in ein Array eingelesen, anschließend beim " , " in verschiedene Spalten aufgeteilt und dann eine ArrayList erstellt.
Jetzt habe ich eine Methode erstellt, die die Duplikate entfernen soll, leider funktioniert dass nicht wie gewollt. Könnte mir bitte jemand auf die Sprünge helfen?

Ich erhalte immer folgende Meldung in der Console:
Exception in thread “main” java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(Unknown Source)
at java.util.AbstractList$Itr.remove(Unknown Source)
at java.util.AbstractList.removeRange(Unknown Source)
at java.util.AbstractList.clear(Unknown Source)
at DatenAuslesenAST.ArrayDaten.duplikateLoeschen(ArrayDaten.java:55)
at DatenAuslesenAST.ArrayDaten.main(ArrayDaten.java:45)

Danke schon mal im voraus.
Grüße

		for (final String line : lines) 
		{
		    String[] valuesArray = line.split(","); 
		    List<String> liste = Arrays.asList(valuesArray);  
			duplikateLoeschen(liste);
		      for (String e : liste)  
		      {  
		         System.out.println(e);
		      }
		}
		}

	  public static void duplikateLoeschen(List<String> liste) {
	    HashSet<String> hashSet = new HashSet<String>(liste);
	    liste.clear();
	    liste.addAll(hashSet);
	  }```

Dein Problem ist, dass du die List die bei Arrays.asList(valuesArray); erstellt wird nicht verändern kannst. Natürlich ist clear() eine Methode die, die Liste verändert.

Wenn du die entsprechende Zeile gegen die austauscht sollte es funktionieren:

 List<String> liste = new ArrayList(Arrays.asList(valuesArray));

So bekommst du eine veränderbare Liste.

Danke schon mal, mein Programm läuft jetzt wieder, aber die Duplikate werden trotzdem nicht entfernt.

Hast du in einer Zeile Duplikate oder nur über alle Zeilen hinweg? Zumindest in einer Zeile sollten keine Duplikate auftreten. Über mehrere Zeilen hinweg kann das natürlich schon passieren. Falls du das nicht möchtest müsstest du das umbauen und das HashSet in jeder Zeile wiederverwenden und um die neuen Einträge erweitern.

Es sind komplett duplikate Datensätze… Also ein gleicher Datensatz kommt mehrmals vor… Wie schon oben erwähnt hab ich ja dann die komplette CSV in ein Array geschrieben, beim " , " getrennt und anschließend in eine ArrayList eingelesen.
Wie meinst du dass mit "in einer Zeile Duplikate? mir werden meine Daten ja jetzt in Listenform ausgegeben pro Zeile 1 Wert.

Dann gib dir doch mal in den zwischen Schritten den Inhalt der Collections aus.

Statt ArrayList einfach ein LinkedHashSet verwenden

Du iterierst über Zeilen. jedenfalls sagt dass dein Code:

for (final String line : lines) {
   String[] valuesArray = line.split(","); // <-- das ist das Array aus dem du Duplikate entfernst. Das gilt nicht für's ganze CSV!
  // hier werden duplikate in der Zeile entfernt
}

Also wenn du z.B. folgendes CSV hast:


pezi,kasperl,kasperl,krokodil
kasperl,oma,pezi,oma

Bekommst du diese Ausgabe:


pezi
kasperl
krokodil
kasperl
oma
pezi

Ist das, das was du möchtest?

Danke, hab ich probiert, irgendwie schmeißt er mir alle Datensätze durcheinander habe ich gerade festgestellt, kann mir aber nicht erklären wieso

*** Edit ***

Ja diese Ausgabe hab ich.
Aber bei mir kommte dieser komplette Datensatz pezi,kasperl,kasperl,krokodil mehrmals in der ganzen CSV Datei vor und das komplette Duplikate soll raus aus dieser CSV Datei… vielleicht bin ich auch etwas falsch an die Sache rangegangen

*** Edit ***
Nochmal zur Erklärung. Ich habe eine CSV Datei bei dem viele 100 Datensätze drinnstehen. Jedoch sind manche Datensätze komplett gleich und diese gleichen Datensätze möchte ich entfernen und da dachte ich mir dass ich alle DS zuerst in ein Array schreibe anschließend in eine ArrayList übergebe und hier die Duplikate rauslösche…

Damit sparst du eine Zeile. Ergebnis ist aber das selbe.

Du musst das HashSet in jeder Zeile mitführen. Also z.B. so:

 
HashSet<String> hs = new HashSet<String>();

for (final String line : lines) {
   String[] valuesArray = line.split(","); // <-- das ist das Array aus dem du Duplikate entfernst. Das gilt nicht für's ganze CSV!
   for(String value : valuesArray) {
     if(!hs.contains(value)) {
       hs.add(value);
       System.out.println(e);
     }
   }
}


Ich vermute ich mach das viel zu umständlich. Ich will einfach nur die Duplikate aus der CSV Datei löschen, sprich den kompletten doppelten Datensatz

Siehe mein Edit oben. Das geht ganz einfach.

Danke schon mal, aber jetzt steig ich gerade gar nicht mehr in meinem Code durch. Und er gibt mir jetzt auch gar nichts mehr zurück.


	public static void main(String[] args) throws IOException {

		// Einlesen
		FileReader myFile = null;
		BufferedReader buff = null;
		final List<String> lines = new ArrayList<String>();

		try {
		myFile = new FileReader("Dateiausgabe.csv");
		buff = new BufferedReader(myFile);
		String line;
		while ((line = buff.readLine()) != null) {
		//System.out.println(line); // kontrolle was eingelesen

		lines.add(line);
		}
		}
		 catch (IOException e) {
			 System.err.println("Fehler:" + e);
			 } finally {
			 try {
			 buff.close();
			 myFile.close();
			 } catch (IOException e) {
			 System.err.println("Fehler:" + e);
		

		HashSet<String> hs = new HashSet<String>();
		 
		for (final String line : lines) {
		   String[] valuesArray = line.split(",");
		   for(String value : valuesArray) {
		     if(!hs.contains(value)) {
		       hs.add(value);
		      System.out.println(e);
		     }
		   }
		}}
	}}

	  public static void duplikateLoeschen(List<String> Arrays) {
	    HashSet<String> hashSet = new HashSet<String>(Arrays);
	    Arrays.clear();
	    Arrays.addAll(hashSet);
	  }}```

Ja, etwas falsch. Die Reihenfolge der Operationen verursacht die Probleme. Wenn Du erst splittest und die Arrays als Elemente einer Collection verwendest, machst Du es Dir bei der Duplikaterkennung unnötig schwer. Zur Erkennung, ob Elemente gleich (und damit Duplikate sind) wird die equals-Methode der Elemente verwendet. Bei Arrays berücksichtigt diese aber die Elemente des Arrays garnicht.

// Speichert die Zeilen ungesplitted. Weils Set ist, werden Duplikate garnicht erst gespeichert
Set<String> uniqueLines= new LinkedHashSet<>();
String line;
// Das Set direkt beim Einlesen der Datei füllen. Es ist unnötig, sich das Ergebnis noch zwischen zu merken.
for((line = bufferedCsvReader.readLine()) != null) {
  uniqueLines.add(line);
}
// An dieser Stelle enthält uniqueLines alle Zeilen ohne Duplikate.
// JETZT kann man darüber dann iterieren und ggf. split aufrufen, um an die Spalten ranzukommen.

Mein Post hat sich gerade mit Deinem überschnitten. Der Code sollte aber trotzdem nützlich sein, um Dir zu zeigen, wie Du Deinen umbauen musst.

duplikateLoeschen kannst du kübeln. Wird ja nicht mehr verwendet, also weg damit. Dann baust du eine Liste von Zeilen auf um dann noch einmal drüber zu iterieren. Aber nur wenn eine IOException geflogen ist. Das schaut falsch aus…

Ungetestet aber ich denke es ist klar wohin die Richtung gehen sollte:

public class ArrayDaten {
 
    public static void main(String[] args) throws IOException {
 
        // Einlesen
        FileReader myFile = null;
        BufferedReader buff = null;
        final List<String> lines = new ArrayList<String>();
 
        try {
           myFile = new FileReader("Dateiausgabe.csv");
           buff = new BufferedReader(myFile);
           String line;
           HashSet<String> hs = new HashSet<String>();
           while ((line = buff.readLine()) != null) {
             String[] valuesArray = line.split(",");
             for(String value : valuesArray) {
               if(!hs.contains(value)) {
                 hs.add(value);
                 System.out.println(e);
               }
             }
           }
         } catch (IOException e) {
             System.err.println("Fehler:" + e);
         } finally {
             try {
                 buff.close();
                 myFile.close();
             } catch (IOException e) {
                 System.err.println("Fehler:" + e);
             }
         }
     }
  }

@nillehammer
Dein Code bringt keinen Vorteil außer es gibt ganze Zeilen von Datensätzen die gleich sind. Das ist aber unwahrscheinlich. Doch dadurch wird der Code unleserlicher und er braucht doppelt so lang.

Ich hatte diesen Satz hier:

genau so verstanden, als wenn es um das entfernen doppelter Zeilen ginge (wegen „kompletter Datensatz“). Und warum, der Code unleserlich ist und doppelt so lange dauern soll, erschließt sich mir auch nicht.

[QUOTE=nillehammer]Ich hatte diesen Satz hier:

genau so verstanden, als wenn es um das entfernen doppelter Zeilen ginge (wegen “kompletter Datensatz”). Und warum, der Code unleserlich ist und doppelt so lange dauern soll, erschließt sich mir auch nicht.[/QUOTE]

Danke euch beiden.

Ja Ziel ist es dass eine komplett gleicher Datensatz aus der CSV-Datei entfernt wird. Ich dachte es wäre am einfachsten mit einer ArrayList, aber wenns anders geht wärs noch besser da ich von ArrayLists noch nich so viel Ahnung habe.

Unleserlicher :wink: Da die Logik auf zwei Schleifen aufgeteilt wird. Unleserlich ist er deswegen noch nicht. Und das ist auch schon die Erklärung warum’s doppelt so lang dauert: Du brauchst zwei Schleifen und gehst zwei mal über die selben Daten drüber. 2*n

Ich denke ein Ansatz aus meinem und deinem Code wäre hier das beste. Eine Schleife in der alles erledigt wird und noch ein Buffer für die Zeilen wenn das tatsächlich öfters auftritt.

********[QUOTE=schlingel]duplikateLoeschen kannst du kübeln. Wird ja nicht mehr verwendet, also weg damit. Dann baust du eine Liste von Zeilen auf um dann noch einmal drüber zu iterieren. Aber nur wenn eine IOException geflogen ist. Das schaut falsch aus…

Ungetestet aber ich denke es ist klar wohin die Richtung gehen sollte:

public class ArrayDaten {
 
    public static void main(String[] args) throws IOException {
 
        // Einlesen
        FileReader myFile = null;
        BufferedReader buff = null;
        final List<String> lines = new ArrayList<String>();
 
        try {
           myFile = new FileReader("Dateiausgabe.csv");
           buff = new BufferedReader(myFile);
           String line;
           HashSet<String> hs = new HashSet<String>();
           while ((line = buff.readLine()) != null) {
             String[] valuesArray = line.split(",");
             for(String value : valuesArray) {
               if(!hs.contains(value)) {
                 hs.add(value);
                 System.out.println(e);
               }
             }
           }
         } catch (IOException e) {
             System.err.println("Fehler:" + e);
         } finally {
             try {
                 buff.close();
                 myFile.close();
             } catch (IOException e) {
                 System.err.println("Fehler:" + e);
             }
         }
     }
  }

@nillehammer
Dein Code bringt keinen Vorteil außer es gibt ganze Zeilen von Datensätzen die gleich sind. Das ist aber unwahrscheinlich. Doch dadurch wird der Code unleserlicher und er braucht doppelt so lang.[/QUOTE]

Ich versteht nich wo du die “e” definiert hast? Das lässt du ja am Ende des try-Blocks ausgeben?

** Nicht dass ihr mich falsch versteht, es sollen nur die Duplikate gelöscht werden, wo der komplette Datensatz gleich ist!

Das soll value und nicht e heißen. Datensatz bedeutet Zeile? Wenn ja, dann kannst du dir das split sparen und die Zeile in das hashset schreiben. Der Rest bleibt gleich.