Array-Filter

Swim

Mitglied
Hallo Leute,

derzeit versuche ich einen Filter für String-Arrays zu erstellen.
Es gib eine gewisse "Schranke" für die länge der jeweilige Strings in einem Array die nicht überboten werden darf.
Kleines Beispiel: Schranke: 5; String-Array:"Hallo","wie","geht","es","dir","Markus";
Wenn ich das Array durch den Filter laufen lasse soll dann folgendes Array zurückkommen:"wie","geht","es","dir". Dementsrechend werden "Hallo" und "Markus" aus dem Array geworfen, da sie länger bzw. gleich der Schranke sind.
Das hier ist mein Entwurf:
Java:
public class ArrayFilter {

	
	
	public static String[] filter(int schranke, String[] aList) {
		
		int l = aList.length;
		String[] kopie = new String[l];
		for (int i = 0; i < aList.length; i++) {
			kopie[i] = aList[i];
		}
		
		for (int i = 0; i < kopie.length; i++) {

			if (kopie[i].length() >= schranke) {
				kopie[i] = null;
				l = l -1;
			}
		}

		for (int i = 0; i < kopie.length; i++) {

			String a = kopie[i];

			if (a == null) {
				

				for (int t = i; t < kopie.length - 1; t++) {
					kopie[t] = kopie[t + 1];

				}

			}
			
			
		}
		
		String[] kopie2 = new String[l];
		for(int s = 0; s < l; s++){
			kopie2[s] = kopie[s];
		}
		
		

		return kopie2;
	}

	public static void main(String[] args) {

		int schranke = Integer.parseInt(args[0]);

		String[] liste = new String[args.length - 1];
		for (int i = 0; i < liste.length; i++)
			liste[i] = args[i + 1];

		String[] bList = filter(schranke, liste);

		for (int i = 0; i < bList.length; i++)
			System.out.println(bList[i]);

	}

}

Mein Problem ist allerdings, dass es nicht immer funktioniert.

Wenn ich jetzt z.B. als Args(5 abc 1234 dontaskme 4321 d zulang) nehme. Funktioniert es.
Wenn ich bei allerdings die Schranke auf 4 setzte kommt abc null raus. Wie kann das sein?
 
Ich würd das ganze etwas simpler angehen.

Java:
public static String[] filter(int schranke, String[] aList) {
  // zählen wieviele Wörter im neuen Array sind
  // neues Array mit der Größe anlegen
  // gefilterte wörter ins neue Array setzen
}

Dann sparst du dir das ganze null setzen und rumgeschiebe.
 
// zählen wieviele Wörter im neuen Array sind
// neues Array mit der Größe anlegen

Klingt gut und ist auch versändlich, allerdings welche gefilterten Werte soll ich dann kopieren, wenn ich sie nicht markiert habe, wie in meinem Fall durch "null"?
 
// zählen wieviele Wörter im neuen Array sind
// neues Array mit der Größe anlegen

Klingt gut und ist auch versändlich, allerdings welche gefilterten Werte soll ich dann kopieren, wenn ich sie nicht markiert habe, wie in meinem Fall durch "null"?

Wozu markieren? Du kannst sie doch direkt in der Schleife checken und fals sie kurz genug sind ins neue Array kopieren.
 
Also ich soll zunächst schauen, wieviele Werte zu lange sind. Eine Kopie des Arrays mit der neuen Länge anlegen.
Soweit so gut, wie kann ich dann die zu Werte mit der richtigen Wortlänge in das neue Array kopieren?
Ich hab zwar die richtige Länge für das Array, aber die Wörter noch nicht.
 
Der Fehler liegt in dem [c]if (a == null){...}[/c]-Block. Wenn du dort an Arrayposition i ein null findest kopierst du den Rest des Arrays (von Index i+1 bis Array.length) um eine Stelle nach vorne. Und dann machst du im nächsten Schleifendurchlauf mit Index i+1 weiter. Das ist jedoch Problematisch sobald mal zwei Nullpointer hintereinander auftreten, weil der jeweils zweite dadurch nicht behandelt wird.


Beispiel (der index i zeige immer auf das fettgedruckte Element):
Aktuelles Array, i sei = 1:
Code:
abc, [b]null[/b], null, null, d, null

Jetzt werden die Elemente von i+1 bis n um eine Stelle nach vorne kopiert.
Array nach dem kopieren:
Code:
abc, [b]null[/b], null, d, null, null

Jetzt müsste man eigentlich dasjenige Element, das neu auf die Position i gewandert ist, auf null hin überprüfen. Bei dir läuft die Schleife aber weiter; i wird erhöht, und zeigt dann schon auf das nächste Element.

Aktuelles Array, i sei jetzt = 2:
Code:
abc, null, [b]null[/b], d, null, null

Dadurch geht dir der Nullpointer an Position 1 durch die Lappen. Und wenn du ganz zum Schluss dein neues Array mit l (=2) Elementen zusammenstellst, dann erhälst du freilich die Elemente [c]abc, null[/c].


Ein einfacher Fix für dieses Problem wäre es in dem [c]if (a == null){...}[/c]-Block noch ein
Code:
i--;[/c] einzufügen, und die Schleife dann nicht bis [c]Array.length[/c] sondern nur bis [c]l[/c] laufen zu lassen:
[code=Java]
        for (int i = 0; i < l; i++) {
            String a = kopie[i];
            if (a == null) {
                for (int t = i; t < kopie.length - 1; t++) {
                    kopie[t] = kopie[t + 1];
                }
                i--;
            }
        }


Schöner wäre es aber wohl wenn du das Array einfach in einer Schleife durchläufst und dabei zwei unabhängige Indizes verwendest. Einen Index i für die Position an der das Array als nächstes ausgelesen wird, und einen zweiten Index j für die Position, an die das zuvor gelesene Element wieder in das Array hereingeschrieben werden soll. j wird nur dann um eins erhöht, wenn kein null-String vorliegt.

Java:
        int j=0;
        for (int i = 0; i < kopie.length; i++) {
            String a = kopie[i];
            if (a != null) {
                kopie[j] = kopie[i];
                j++;
            }
        }
 
Huch, wo hast du denn den Begriff her? Eine Aufrufkonvention könnte man ganz allgemein als einen Weg um eine Funktion/Methode aufzurufen und ihr Daten zu übergeben (und Daten von ihr zurückzubekommen) beschreiben. Der Begriff wird allerdings eher in einem anderen Kontext verwendet (beim Bau von Compilern).

Wenn man bei Java-Quellcodes von Aufrufkonvention redet dann könnte ich mir vorstellen das man damit zwei verschiedene Dinge meinen kann:

1) die sog. Signatur einer Methode, z.B. [c]public static String[] filter(int schranke, String[] aList)[/c]. Hier wird festgelegt mit welchen Parametern in welcher Reihenfolge die Methode aufgerufen wird und was die Methode zurückliefert

2) die Unterscheidung zwischen Call by Value und Call by Reference.

Hilft dir das weiter?
 
Java:
public static String[] filter(int schranke, String[] aList) {
  // zählen wieviele Wörter im neuen Array sind
  // neues Array mit der Größe anlegen
  // gefilterte wörter ins neue Array setzen
}
Das könnte man z.b. so umsetzen:
Java:
	public static String[] filter(int schranke, String[] aList) {
		int counter = 0;
		for (String s : aList) {
			if (s.length() < schranke) {
				counter++;
			}
		}
		
		String[] filtered = new String[counter];
		
		int itemCounter = 0;
		for (String s : aList) {
			if (s.length() < schranke) {
				filtered[itemCounter++] = s;
			}
		}
		
		return filtered;
	}
Find ich leichter verständlich als das null setzen, verschieben, etc.
 
Huch, wo hast du denn den Begriff her? Eine Aufrufkonvention könnte man ganz allgemein als einen Weg um eine Funktion/Methode aufzurufen und ihr Daten zu übergeben (und Daten von ihr zurückzubekommen) beschreiben. Der Begriff wird allerdings eher in einem anderen Kontext verwendet (beim Bau von Compilern).

Wenn man bei Java-Quellcodes von Aufrufkonvention redet dann könnte ich mir vorstellen das man damit zwei verschiedene Dinge meinen kann:

1) die sog. Signatur einer Methode, z.B. [c]public static String[] filter(int schranke, String[] aList)[/c]. Hier wird festgelegt mit welchen Parametern in welcher Reihenfolge die Methode aufgerufen wird und was die Methode zurückliefert

2) die Unterscheidung zwischen Call by Value und Call by Reference.

Hilft dir das weiter?

Dein erster (1.) Vorschlag hat mich überzeugt und müsste das Richtige sein.
Vielen Dank für die großartige Unterstützung.
 
Spricht irgendwas dagegen, einfach vernünftige Collections zu nehmen?

Immer noch nicht schön, aber immerhin einigermaßen übersichtlich:

Java:
	static List<String> filter(List<String> list, int maxLen) {
		List<String> filteredList = new ArrayList<>();
		for (String elem : list) {
			if (elem.length() <= maxLen)
				filteredList.add(elem);
		}
		return filteredList;
	}
 

Neue Themen


Zurück
Oben