ubuntuusers.de

Java: Wie über eine Liste mit int's loopen?

Status: Gelöst | Ubuntu-Version: Ubuntu 12.04 (Precise Pangolin)
Antworten |

Kerberos

Anmeldungsdatum:
18. Juni 2007

Beiträge: 330

In Python kann man super über Listen loopen, zB:

1
2
for prime in list[2,3,5,7,11,17]:
    result = test(prime)

Geht sowas auch irgendwie in Java, oder wie macht man das am elegantesten? Ich habe eine Anzahl von Zahlen deren Eigenschaft ich testen will.

coffeeholic Team-Icon

Avatar von coffeeholic

Anmeldungsdatum:
10. August 2012

Beiträge: 1938

Wohnort: ::1

Ein Array verwenden du willst. *jedihandmove*

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17622

Wohnort: Berlin

Hängt davon ab, was 'test' in Deinem Beispiel macht. Filtert es manche Zahlen aus? (Wieso ist 13 nicht in den primes?)

Dann geht nicht so einfach, sondern dann brauchst Du die Deklaration einer Ergebnisliste unbekannter Länge, weswegen ein Array eine denkbar schlechte Lösung ist:

1
2
3
List <Integer> primes = new List <Integer> ();
for (Integer i : list) 
   if (primTest (i)) primes.add (i); 

Ich kann kein Python, daher zögere ich etwas.

Kerberos

(Themenstarter)

Anmeldungsdatum:
18. Juni 2007

Beiträge: 330

test() ( besserer Name wär isPrime() ) sagt nur true oder false, also ob die Zahl eine Primzahl ist oder nicht. Die 13 hab ich nur vergessen hinzuschreiben. Python nimmt immer die erste Zahl in der Liste, schreibt sie auf prime geht in die Schleife, macht was mit prime, geht wieder raus und nimmt die nächste Zahl bis keine mehr da sind.

Sinn der Sache war die isPrime() mit Stichproben von Primzahlen zu testen, um herauszufinden, ob ich auch keinen Fehler eingebaut habe. Wenn irgendwas schief geht soll es ausgeben, welche Zahl aus der Liste nicht gefunden wird und abbrechen, wenn alles fehlerfrei durchläuft kommt ein System.out.println("tests pass") am Ende.

So hab ich es immer in Python gemacht, keine Ahnung ob es bei Java irgendwelche Tools zum testen gibt die das alles etwas vereinfachen.

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Wenn die Primzahlen feststehen, würd ich's nach diesem Schema machen:

1
2
3
for (int prime : new int[]{2, 3, 5, 7, 11, 13, 17}) {
    System.out.println(prime);
}

Ich bin allerdings kein Java-Experte.

//edit: Oder mit ner richtigen Liste:

1
2
3
4
5
6
7
8
9
import static java.util.Arrays.asList;

public class PrimeTest {
    public static void main(String[] args) {
        for (int prime : asList(2, 3, 5, 7, 11, 13, 17)) {
            System.out.println(prime);
        }
    }
}

Oder halt mit Binden an ner Variablen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import java.util.List;

import static java.util.Arrays.asList;

public class PrimeTest {
    public static void main(String[] args) {
        List<Integer> primes = asList(2, 3, 5, 7, 11, 13, 17);
        for (int prime : primes) {
            System.out.println(prime);
        }
    }
}

Ich komm auch von Python und mag dieses asList() sehr wie man merkt. ☺

Listen würd ich halt nur nutzen, wenn später noch was dazukommen oder rausgenommen werden soll. Ansonsten lieber Array (s. mein erstes Codebeispiel).

Kerberos

(Themenstarter)

Anmeldungsdatum:
18. Juni 2007

Beiträge: 330

Danke das erste Bsp. funktioniert schon super. Werde da aber wohl nochmal nachlesen müssen um zu kapieren was genau passiert.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17622

Wohnort: Berlin

Weil die Zuweisung im Beispielcode den Wert des letzten Tests wiedergibt ist dieser Code nicht so sinnvoll - so ganz allgemein könnten Arrays oder Listen geeignet sein.

Grade für wiederkehrende Operationen auf Sammlungen haben viele Sprachen automatisierte Vereinfachungen, etwa bei Scala, zum Test auf ein Prädikat, sprich, eine Methode die eine Eigenschaft auf wahr/falsch testet:

1
list.filter (_ % 2 == 0) 

oder gleich mit Zuweisung

1
val gerade = list.filter (_ % 2 == 0) 

oder Primzahlen

1
val primes = (1 to 20).filter (isPrime) 

Oder für for-comprehensions

1
2
3
val primes = for (i <- (1 to 20)
  if (isPrime (i)) 
    yield i

Das yield im letzten Beispiel hat die merkwürdige Eigenschaft, das beim Durchlaufen ein Ergebnis geliefert wird, ähnlich wie bei einem return, aber die Schleife wird nicht verlassen, sondern es wird weitergeloopt. Das i wird also nur auf die Palette gestellt, aber die Palette wird noch nicht auf den LKW geschoben - erst wenn die Schleife durchgelaufen ist werden die passenden Werte zurückgegeben.

Ich dachte auf sowas wärst Du aus.

Java hat derlei syntaktischen Zucker nicht. Das einzig halbwegs moderne Feature ist die vereinfachte for-loop und ein einheitlicher Zugriff auf Listen/Arrays/Sets/Maps und das Autoboxing von eingebauten Typen (int, long, float, ...)

1
2
3
for (DEKLARATION name: COLLECTION) {
  tu.was.mit (name); 
}

Ohne externe Library ist das filtern/mappen usw. auf Listen mit viel Codezermoniell verbunden.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Kerberos schrieb:

Geht sowas auch irgendwie in Java, oder wie macht man das am elegantesten? Ich habe eine Anzahl von Zahlen deren Eigenschaft ich testen will.

Auch wenn die Frage an sich schon beantwortet wurde, so möchte ich hier doch noch mal auf die Java Tutorials hinweisen. Dort solltest Du Dir dringend mal das Kapitel über Collections durchlesen und ggf. auch das zu Generics.

@snafu1: Da die Zahlen ja nicht vom Himmel fallen dürften, würde ich die Lösung mit der Liste *immer* zunächst einer anderen Lösung mittels Arrays vorziehen. Um sich doppelte Arbeit zu ersparen, könnte man natürlich auch gleich zu einem Set-Typen greifen. Aber das hängt natürlich schon davon ab, was mit den Zahlen noch passieren soll.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17622

Wohnort: Berlin

Lysander schrieb:

@snafu1: Da die Zahlen ja nicht vom Himmel fallen dürften, würde ich die Lösung mit der Liste *immer* zunächst einer anderen Lösung mittels Arrays vorziehen. Um sich doppelte Arbeit zu ersparen, könnte man natürlich auch gleich zu einem Set-Typen greifen. Aber das hängt natürlich schon davon ab, was mit den Zahlen noch passieren soll.

Wenn die Größe des Arrays vorab bekannt ist, und außerdem bekannt ist, dass sich diese zur Laufzeit nicht ändert, dann spricht wenig gegen ein Array. Vielleicht dass Operationen, die für eine List (Set, ...) direkt aufrufbar sind bei Arrays den Aufruf statischer Hilfsmethoden erfordert, was ein kl. Umweg ist.

Dafür ist das initialisieren eines Arrays manchmal praktischer.

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Naja, wenn Elemente später hinzukommen, dann würde ich auch zu einer Liste greifen. Bei vorher feststehender Größe der Liste bietet es sich immer noch an, diese Größe bei der Listenerzeugung mit anzugeben (für 50 Elemente also List<Integer> primes = new ArrayList<>(50)), damit man sich teure Verschiebungsaktionen ersparen kann. Wenn denn der dadurch erhaltene Performancevorteil überhaupt eine (messbare) Rolle spielt.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

user unknown schrieb:

Wenn die Größe des Arrays vorab bekannt ist, und außerdem bekannt ist, dass sich diese zur Laufzeit nicht ändert, dann spricht wenig gegen ein Array. Vielleicht dass Operationen, die für eine List (Set, ...) direkt aufrufbar sind bei Arrays den Aufruf statischer Hilfsmethoden erfordert, was ein kl. Umweg ist.

Sicher. Aber ich würde genau diese Fälle als Ausnahmen bezeichnen - ggf. kommt so etwas in Spezialdisziplinen (Grafik, MSR, usw.) öfter mal vor. Daher sollte man imho zuerst an eine generische und dynamische Lösung denken.

Dafür ist das initialisieren eines Arrays manchmal praktischer.

Ok, stimmt. Java fehlt da einiges an Literalen... das sollte sich Oracle mal bei C# abgucken. Andererseits: Wie oft initialisiert man denn Objekte mit x fixen Werten? 😉

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13212

Lysander schrieb:

user unknown schrieb:

Wenn die Größe des Arrays vorab bekannt ist, und außerdem bekannt ist, dass sich diese zur Laufzeit nicht ändert, dann spricht wenig gegen ein Array. Vielleicht dass Operationen, die für eine List (Set, ...) direkt aufrufbar sind bei Arrays den Aufruf statischer Hilfsmethoden erfordert, was ein kl. Umweg ist.

Sicher. Aber ich würde genau diese Fälle als Ausnahmen bezeichnen - ggf. kommt so etwas in Spezialdisziplinen (Grafik, MSR, usw.) öfter mal vor. Daher sollte man imho zuerst an eine generische und dynamische Lösung denken.

Auf jeden Fall sollte man nicht zu früh optimieren...

Dafür ist das initialisieren eines Arrays manchmal praktischer.

Ok, stimmt. Java fehlt da einiges an Literalen... das sollte sich Oracle mal bei C# abgucken. Andererseits: Wie oft initialisiert man denn Objekte mit x fixen Werten? 😉

Eben. Und für die paar Fälle gibt es ja auch noch

1
2
3
		for (final int prime : Arrays.asList(2, 3, 5, 7, 11, 13, 17)) {
			System.out.println(prime);
		}

Ciao

robert

fnumatic

Anmeldungsdatum:
20. Februar 2007

Beiträge: 379

user unknown schrieb:

Das yield im letzten Beispiel hat die merkwürdige Eigenschaft, das beim Durchlaufen ein Ergebnis geliefert wird, ähnlich wie bei einem return, aber die Schleife wird nicht verlassen, sondern es wird weitergeloopt. Das i wird also nur auf die Palette gestellt, aber die Palette wird noch nicht auf den LKW geschoben - erst wenn die Schleife durchgelaufen ist werden die passenden Werte zurückgegeben.

guter bildhafter Vergleich.

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Wobei sich mir da die Frage stellt, ob ihr yield wirklich verstanden habt. Schon mit dem ersten yield lässt sich der ausgegebene Wert weiterverarbeiten. Sei es durch weitere Iterationen (z.B. mittels for-Schleife) oder dass man sich einfach nur einen Teil zur Weiterverarbeitung abholt (etwa list(itertools.islice(iter_items(), 10)) für die ersten 10 Rückgaben von iter_items() als Liste). yield bedeutet ausdrücklich nicht, dass man das Ende der Schleife abwarten müsste, bevor man weitermachen kann.

fnumatic

Anmeldungsdatum:
20. Februar 2007

Beiträge: 379

verstehe dein Beispiel nicht...

und ich glaube schon, dass ich "for comprehensions" (in Scala) verstanden habe

1
for(e <- l) yield {...}

wird zu

1
l.map(e =>{...})
Antworten |