Frage von iFeelOffended, 10

Fehler im algorithmus?

Hallo zusammen,

momentan schreibe ich an einem kleinen Algorithmus, bzw. Programm. Ich bin mir jetzt nicht sicher, inwiefern es nötig ist das alles genau zu erklären...

Jedenfalls hatte ich folgendes Script:

for (int i = 0; i <  aushilfsliste.size() ; i++) {
                int v = aushilfsliste.get(i).lastIndexOf('\'');
                int u = aushilfsliste.get(i).lastIndexOf('\'', v - 1);
                str3.add(i , aushilfsliste.get(i).substring(u+1, v));
                //statt textZeile.length textZeile.size()
                for (int j = 0 ; j < textZeile.size() ; j++){
                    if (str3.get(i).equalsIgnoreCase(str1.get(j)) && aushilfsliste.get(i).contains(str2.get(j)) && i!=j) {
                            System.out.println( System.lineSeparator()+"Schleife bei Zeile: " + i +  ": " + aushilfsliste.get(i).replaceAll("[&$/^\\[\\]]","")  + "'" + str2.get(j).replaceAll("[&$/^\\[\\]]","") + "'");
                            aushilfsliste.remove(i);
                            i=i-1;
                            j=j-1;
                    } else if (str3.get(i).equalsIgnoreCase(str1.get(j))) {
                            aushilfsliste.add(aushilfsliste.get(i)  + "'" + str2.get(j) + "'" + "[]");
                    }
                }
            }

, wobei allerdings der Fehler:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 2237 , Size: 2237
    at java.util.ArrayList.rangeCheck<ArrayList.java: 635>
    at java.util.ArrayList.get<ArrayList.java:411>

mit Verweis auf die If-Bedingung angezeigt wurde.

Hab dann ein wenig nachgelesen und wollte das ganze dann mit iteration() machen, sah dann so aus:

            Iterator<String> itAushilfsliste = aushilfsliste.iterator();
            Iterator<String> itTextZeile =textZeile.iterator();
            int q = 0;
            int r = 0;
            while (itAushilfsliste.hasNext()){
                int v = aushilfsliste.get(q).lastIndexOf('\'');
                int u = aushilfsliste.get(q).lastIndexOf('\'', v - 1);
                str3.add(q , aushilfsliste.get(q).substring(u+1, v));
                //statt textZeile.length textZeile.size()
                while (itTextZeile.hasNext()){
                    if (str3.get(q).equalsIgnoreCase(str1.get(r)) && aushilfsliste.get(q).contains(str2.get(r)) && q != r){
                            System.out.println( System.lineSeparator()+"Schleife bei Zeile: " + q +  ": " + aushilfsliste.get(q).replaceAll("[&$/^\\[\\]]","")  + "'" + str2.get(r).replaceAll("[&$/^\\[\\]]","") + "'");
                            itTextZeile.next();
                            itAushilfsliste.next();
                            itAushilfsliste.remove();
                    } else if (str3.get(q).equalsIgnoreCase(str1.get(r))) {
                            aushilfsliste.add(aushilfsliste.get(q)  + "'" + str2.get(r) + "'" + "[]");
                    }
                    r=r+1;
                }
                q=q+1;
            }

Tritt nur leider noch immer genau der selbe Fehler auf...kann mir evtl. jemand auf die schnelle sagen woran das ganze liegt? Meine eigentliche vermutung war, dass ich .remove() innerhalb einer Schleife nicht machen kann, aber da es mit literation() auch nicht klappt finde ich meinen fehler nicht so ganz (oder ist da nen Fehler bei dem Iteration selbst????).....ach ja, compilieren klappt ohne Probleme, der Fehler kommt erst wenn ich das Programm laufen lassen will.

Danke schon mal im Voraus:)

Antwort
von PWolff, 6

Innerhalb von Iteratoren (foreach und Verwandte) sollte man die Liste, über die iteriert wird, IMMER als schreibgeschützt behandeln, auch wenn der Compiler es nicht tut.

Wenn man per Zähler/Index über eine Liste iteriert und innerhalb des Schleifenkörpers Elemente löscht und/oder einfügt, sollte man den Index IMMER von oben nach unten laufen lassen - sonst kommt man allzu leicht durcheinander:

for (index=list.length-1; index>=0; index--) { ... };

(Es ist natürlich auch möglich, den Index vorwärts laufen zu lassen und bei Löschungen die Änderung entsprechend zu berücksichtigen - ich verwende hier eine while-Schleife, weil ich der Ansicht bin, dass auch die Zählvariable in einer for-Schleife für den Schleifenkörper als schreibgeschützt zu betrachten ist:

index=0;
while(index<list.length) {
elementEntfernt=false;
doStuff; // hierbei ggf. elementEntfernt setzen
// if(!elementEntfernt) { index++; ];
};

aber ich finde das wesentlich unübersichtlicher und damit schwerer zu warten.)

Kommentar von iFeelOffended ,

wie genau behandel ich denn die Liste als schreibgeschützt? hab davon nch nie was gehört...

meinst du mit von oben nach unten durchgehen vom element mit dem größten wert in der Liste bis zum 0-ten Element?

Kommentar von PWolff ,

Als schreibgeschützt behandeln: keinen Schreibzugriff reinschreiben

Ja, v. o. n. u. heißt hier genau dies. (Hab vergessen, den Schleifenkopf als Code zu formatieren)

for (index=list.length-1; index>=0; index--) { ... };
Expertenantwort
von KnusperPudding, Community-Experte für Java, 4

Eins der Hauptprobleme bei deinem Algorithmus ist das mischen von Schleifen-Zugriffen:

Hast du eine Liste:

List<String> myElements = new ArrayList<>();

Und du durchläufst deine Liste via Iterator, sollte der Zugriff so aussehen:

Iterator<String> myElementsItr = myElements.iterator();
while (myElementsItr.hasNext() {
   String currentElement = myElementsItr.next();
}

Und nicht mit Index anfangen.

Kommentar von iFeelOffended ,

Okay, aber warum ist es in der dritten Zeile so wichtig noch einmal

String currentElement = myElementsItr.next();

zu schreiben? oder war das jetzt nur ein Beispiel? weil das drumherum hab ich doch so ähnlich gemacht. Oder meinst du das damit ich befehle wie remove() o.Ä. dann im folgenden über currentElement.remove() mache? Sorry wenn ich das gerade nicht so ganz verstehe...

Antwort
von DocShamac, 6

Dein Problem entsteht wahrscheinlich, weil du aus deiner ArrayList Elemente entfernst, während du darüber iterierst. Das vertragen ArrayLists nicht gut.

(Eine IndexOutOfBoundsException tritt auf, wenn du versuchst auf ein Array-Element zuzugreifen, indem du einen Index verwendest, den es nicht (mehr) gibt.)

Ich würde dir empfehlen, Löschentscheidung und Löschen zu trennen.

  1. Du iterierst über alle Elemente und merkst dir dann, welche du löschen möchtest.
  2. Danach (außerhalb der Schleife) nimmst du dann genau diese Element aus der ArrayList heraus.

Kommentar von iFeelOffended ,

Hatte ich mir zwischenzeitlich auch gedacht, aber ListIterator ist doch genau dafür da, dass man das eben nicht so machen muss oder?

Kommentar von DocShamac ,

Ich muss zugeben, dass ich deine Frage nicht vollständig gelesen hatte. Der Code wird hier ziemlich unleserlich dargestellt.

Ich habe den fraglichen Code-Abschnitt gesehen (aushilfsliste.remove(i);) und dann gemeint, dass das der Fehler ist.

Dein zweiter Code-Snippet enthält aber diesen Fehler nicht. Auf Anhieb finde ich den Fehler nicht. Ich schaue mir das noch einmal genauer an.

In welcher Code-Zeile tritt der Fehler denn auf? Bei itAufhilfsliste.remove();?

Kommentar von iFeelOffended ,

okay, danke sehr:)

Kommentar von iFeelOffended ,

ne, in der if bedingung davor, glaube aber dass der eigentliche Fehler der remove() ist....


if (str3.get(q).equalsIgnoreCase(str1.get(r)) && aushilfsliste.get(q).contains(str2.get(r)) && q != r){



Kommentar von DocShamac ,

Der Fehler liegt aber wohl in dieser Zeile. Dein Codeausschnitt sagt mir nicht, was str3 und str1 sind, aber ich nehme an, dass darin in einem von beiden keine Elemente enthalten sind.

Oder der Zugriff auf aushilfsliste.get(q) geht schief, falls alle Elemente entfernt wurden.

Außerdem ist mir aufgefallen, dass q und r während des gesamten Durchlaufs den Wert 0 haben. War das deine Absicht?

Insgesamt erscheint es mir nicht schlau, Elemente aus der Aushilfsliste zu entfernen und dann doch wieder direkt über aufhilfsliste.get(q) auf einzelne Element zugreifen zu wollen.

Kommentar von iFeelOffended ,

hmm, also eigentlich haben die alle nen Inhalt....aber ich guck noch mal^^

Und warum sind q und r die ganze zeit 0??? hab doch innerhalb der while schleife immer q=q+1 und r=r+1

Kommentar von DocShamac ,

Stimmt ja. :)

Mein Tipp geht auf aushilfsliste.get(q) in der if-Zeile. Du greifst da direkt über den Index auf die aushilfsliste zu. q wird jeden Durchlauf um eins erhöht. Das heißst du fragst hier JEDEN Index ab. Wenn vorher ein Element entnommen wurde, dann muss das fehlschlagen.


Kommentar von iFeelOffended ,

stimmt, da hatte ich gar nicht dran gedacht...daran könnte es echt liegen^^

Kommentar von iFeelOffended ,

es will immer noch nicht:/

Kommentar von DocShamac ,


Vertraue darauf, dass der Fehler in der if-Zeile liegt! Da stimmt etwas nicht mit dem Index, den du verwendest in Bezug auf das Array, das zugrundeliegt!

Hast du es schon mit Minimierung versucht?

  1. Sorge dafür, dass pro Zeile nur eine Anweisung ausgeführt wird. Dann kommst du leichter dahinter, wo der Fehler genau auftritt.
  2. Wirf einzelne Anweisungen raus, bis der Fehler nicht mehr auftritt.

Danach kannst du deinen Code nochmal posten. Und bitte genau mitteilen, in welcher Zeile die Exception geworfen wird.


Kommentar von iFeelOffended ,

hast recht gehabt, aus ieinem Grund war ein Element der aushilfsliste null, da kann das natürlich nicht funktionieren^^" mein Fehler...tut mir echt leid dass ich euch eure Zeit genommen hab!!! jetzt nur noch heraus finden was ich da wieder falsch gemacht hab...-.-"

Keine passende Antwort gefunden?

Fragen Sie die Community

Weitere Fragen mit Antworten