ArrayList löscht alle Elemente bis auf eines

werdas34

Bekanntes Mitglied
Hallo,
ich habe eine ArrayList und möchte da am Ende alle Elemente die größer als 3 sind, aus der Liste löschen.

Hier mal der Inhalt der Liste:
Code:
[Yy, AXY, AYYY, SAY, SXX, SXY, SYA, SAYAA, Xx, SYAA, SYYY, SAYA, SAA, SXAX, AY0, 0YY, SA1, 1YAA, SY2, 2AA, SA3, 3YA, SX4, 4AX, 1Y5, 5AA]

Darauf folgen dann diese Anweisungen:
Java:
        for (int i = 0; i < list.size(); i++) {
            if (((String) list.get(i)).length() > 3) {
                list.remove(i);
            }
        }

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println();
Als Ergebnis erhalte ich:
Code:
Yy
AXY
SAY
SXX
SXY
SYA
Xx
SYYY
SAA
AY0
0YY
SA1
SY2
2AA
SA3
3YA
SX4
4AX
1Y5
5AA
Ich verstehe nicht warum "SYYY" übersprungen wird. Selbst im Debugger, wenn man sich das ansieht, sieht man wie jeder Inhalt der größer als 3 ist, gelöscht wird, außer "SYYY".

Gibt es eine Möglichkeit, dies zu umgehen? Sowas wie Sets nur eben für eine bestimmte Größe?

Hier nochmal der ganze Code:
Code:
import java.util.ArrayList;
import java.util.HashSet;

public class CFG2CNF {

    public static void main(String[] args) {
       
        String[] prod2= {"SxAx", "SAyAA", "SAA", "SyAA", "Sxx", "SAyA", "Sxy", "Syyy",
                "SyA", "SAy", "Axy", "Ayyy"};
        CFG2CNF(prod2);
    }
   
    public static boolean onlyUpperCase(String test) {
        for (int i = 0; i < test.length(); i++) {
            if (!Character.isUpperCase(test.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    public static void removeDuplicatedEntries(ArrayList<String> arrayList) {
        HashSet<String> hashSet = new HashSet<String>(arrayList);
        arrayList.clear();
        arrayList.addAll(hashSet);
    }
   
    public static void CFG2CNF(String[] prod) {
        ArrayList list = new ArrayList();
       
        // Wandelt die Terminale in Nonterminale um und fügt die wichtigen Regeln der
        // Liste hinzu.
        for (int i = 0; i < prod.length; i++) {
            for (int j = 0; j < prod[i].length(); j++)
                if (Character.isLowerCase(prod[i].charAt(j)) && prod[i].length() > 2) {
                    char character = prod[i].charAt(j);
                    char characterUpper = Character.toUpperCase(prod[i].charAt(j));
                    String newRule = String.valueOf(characterUpper) + character;
                    String changedIntoNonterminal = returnOnlyUpper(prod[i]);

                    list.add(newRule);
                    list.add(changedIntoNonterminal);
                }
            if (Character.isLowerCase(prod[i].charAt(1)) && prod[i].length() == 2) {
                list.add(prod[i]);
            }
            if (onlyUpperCase(prod[i])) {
                list.add(prod[i]);
            }

        }
       

       
        // Trennt die Grammatik richtig.
        removeDuplicatedEntries(list);
        int j = 0;
        for (int i = 0; i < list.size(); i++) {

            String help = (String) list.get(i);
            if (help.length() > 3) {
                String shortRule = help.substring(0, 2) + j;
                String newShortRule = j + help.substring(2, help.length());
                list.add(shortRule);
                list.add(newShortRule);
                j++;
                i = i + 1;
            }
        }
       
        for (int i = 0; i < list.size(); i++) {
            if (((String) list.get(i)).length() > 3) {
                list.remove(i);
            }
        }

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println();
    }
   
    static String returnOnlyUpper(String test) {
        for(int i = 0; i < test.length(); i++) {
            if(!Character.isUpperCase(test.charAt(i))){
                char letterLow = test.charAt(i);
                char letterBig = Character.toUpperCase(letterLow);
                test = test.replace(letterLow, letterBig);
            }
        }
        return test;
    }
   
   
   
    }
 
Du hast immer dann ein Problem, wenn 2 Elemente die Länger als 3 sind hintereinander auftreten.
Stell dir folgendes vor:
["xyz","xyza","xyzb", "a"].

Bei Listen ist es so, dass die Elemente nach dem gelöschten Element nachgerückt werden. D.h. dein Algorithmus würde jetzt folgendes tun:
Code:
 i   löschendes Element    Liste nach löschen
 0        -                ["xyz","xyza","xyzb","a"]
 1        "xyza"           ["xyz","xyzb","a"]
 2        -                ["xyz","xyzb","a"]
Das Elemente welches zu Groß ist "xyzb" wird also vom Algorithmus nicht erkannt weil es nach dem löschen des Vorgängers nach vorne rutscht.

Entweder nutzt du dazu die seit Java8 existierende Stream-Api um deine Liste zu ändern
Java:
list.removeIf(e -> e.length() > 3);
oder du verringerst den Index i in deiner Schleife immer um 1 wenn ein Element gelöscht wurde, um auch das Element zu berücksichtigen welches nachgerutscht ist.
Java:
// Hausaufgabe ;)
 
Zu den beiden richtigen Antworten hier noch eine Alternative: Zähl abwärts
Code:
for (int i = list.size() - 1; i >=0; i--) {
//...
Damit hast du das Problem des Überspringens nicht.
Als kleiner Bonus wird .size() auch nur ein einziges Mal aufgerufen anstatt nach jedem Durchgang.
 

Zurück
Oben