Lottozahlen

javastudent25

Bekanntes Mitglied
Hallo Freunde

Mich hat es mal interessiert einen Lottozahlenzufallsgenerator zu programmieren und der Algorithmus, wie doppelte Einträge vermieden werden.

Der Code ist sicher sonst auch verbesserungswürdig, aber ich bekomme es irgendwie auch ideentechnisch nicht auf die Reihe, es zu vermeiden, dass doppelte Zahlen vorkommen.
Irgendwie habe ich das Problem, dass ich zwar Schritt für Schritt vorgehe und bei Differenz 0 eine neue Zahl generiere, aber dann auch wieder zurück gehen muss um zu prüfen, ob er nicht eine neue Zahl generiert hat, die zuvor irgendwo war...
hmm, irgendwie lustig, ich steh da voll daneben.

Es ist die Methode entferneGleicheZahl()

Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Random;

public class eugen {
    static int zahl = 0;
    static int num = 0;
    static String name1;
    static int alter;
    static String begriff;
    static int[] zufallsZahlen = new int[6];
    static Random rand = new Random();
    static int x = 0;

    public static void main(String[] args) {
        erzeugeZahl();
        entferneGleicheZahl();
        zahlenAusgeben();
    }

    public static void entferneGleicheZahl() {
        int s = 0;
        int m = 1;
        int i;
        int y;

        for (y = 0; y < (zufallsZahlen.length - 1); y++) {
            s = zufallsZahlen[y];
            for (i = m; i < zufallsZahlen.length; i++) {
                while ((s - zufallsZahlen[i]) == 0) {
                    zufallsZahlen[i] = rand.nextInt(42) + 1;
                    for (int b = i; b > 0; b--) {
                        if ((zufallsZahlen[b] - zufallsZahlen[b - 1]) == 0) {
                            while ((zufallsZahlen[b] - zufallsZahlen[b - 1]) == 0) {
                                zufallsZahlen[b - 1] = rand.nextInt(49) + 1;
                            }
                        }
                    }
                }
                m++;
            }
        }
    }

    public static void zahlenAusgeben() {
        Arrays.sort(zufallsZahlen);
        for (int i = 0; i < zufallsZahlen.length; i++) {
            System.out.print(zufallsZahlen[i] + " ");
        }
    }

    public static void erzeugeZahl() {
        int i = 0;

        for (i = 0; i < zufallsZahlen.length; i++) {
            num = rand.nextInt(42) + 1;
            zufallsZahlen[i] = num;
        }
    }

    public static void erzeugeGlueckszahl() {
        int glk1 = 0;
        int glk2 = 0;
        int a;
        for (int i = 0; i < 1; i++) {
            a = rand.nextInt(6) + 1;
            if (i == 0) {
                glk1 = a;
            }
        }
        zufallsZahlen[6] = glk1;
    }
}
 
Zuletzt bearbeitet von einem Moderator:
K

kneitzel

Gast
Also dein Vorgehen verstehe ich hier jetzt nicht ganz. Dein Algorithmus ist ja mehr als komplex und das kann ich im Augenblick nicht nachvollziehen.

Also als erstes würde ich bemängeln, dass es nicht objektorientiert ist. Da würde ich dran arbeiten.

Dann sehe ich zwei Möglichkeiten, wie man sinnvoll vorgehen kann:
a) Direkt bei der Erzeugung einer Zufallszahl wird die Gültigkeit geprüft. Also direkt mit jeder neuen Zahl wird geprüft, ob diese schon vorkommt. Dann hat man einen ganz einfachen Algorithmus:
- Solange noch keine 6 Zahlen gezogen wurden:
-- Ziehe eine Zahl
-- Falls Zahl noch nicht in gezogenen Zahlen, dann füge Zahl hinzu
Ganz trivial und einfach zu verstehen. Anders als Deine verschachtelten Schleifen.

b) Du kannst es so machen, wie es auch physikalisch funktioniert. Du hast ein Array von Lottokugeln (int Werte). Du initialisierst die Werte von 1 bis 49 (Wie kommst Du auf 42 oder habe ich mich versehen?). Und wenn Du feste Arrays nutzt, dann musst Du noch merken, wie viele Kugeln vorhanden sind.
Nun ziehst Du eine Kugel:
- Zufallszahl ermitteln (1-Anzahl Kugeln).
- Nun merkst Du den Wert der Kugel (Array-Element von Zufallszahl-1 auslesen)
- Nun schiebst Du die letzte Kugel an die Stelle (Also den Wert von AnzahlKugeln -1 in Zufallszahl-1 schreiben)
- AnzahlKugeln um 1 reduzieren.
Dann hast Du einfach die physikalische Maschine im Code umgesetzt.

Allgemeine Hinweise:
- Sobald du mehr als 2 Schleifen verschachtelt hast, dann hast Du schon unleserlichen Code und Du hast es umzuschreiben! Lager Dinge in Funktionen aus! Ich habe nur eine Schleife in meinem angegebenen Algorithmus, aber die Unterfunktionen können natürlich jeweils auch wieder Schleifen enthalten. Aber das sieht man denn nicht direkt sondern hat alles schön übersichtlich.
- Wähle gute Namen für deine Variablen. Ist ja absolut grausig!
 

javastudent25

Bekanntes Mitglied
Hallo Konrad

Danke für deine schnelle Reaktion.
Es ist mir im Moment auch weniger darum gegangen, alles objektorientiert zu gestalten, da mir der Vorgang des doppelten Eintrags wichtig war.
Fall a verstehe ich und ich weiss man sollte sich das Leben nicht allzu schwer machen, aber ich möchte den Algorithmus trotzdem so haben, wenn die Zahlen gezogen und im Array sind.

Fall b habe ich mir jetzt 3 mal durchgelesen, aber irgendwie leuchtet mir nicht ein, was
Zufallszahl-1, 1-Anzahl KUgeln, und AnzahlKugeln-1 in Zufallszahl-1 sein soll.
kannst du das mal vllt so schreiben Array[i-1] oder sowa?

PS: 42 deshalb, weil wir in der Schweiz zu wenig Kugeln haben... ;) Österreich liegt da sogar 3 Punkte vorn.
Aber ihr, das Deutsche Reich, seid die Führer. Hat wohl anscheinend mit der Fläche der einzelnen Länder zu tun :D :D
 
K

kneitzel

Gast
Also Du hast ein Array kugeln vom typ int[], Größe 42. Das füllst Du mit den Zahlen von 1 - 42.

Nun kannst Du eine Zahl ziehen. Dazu brauchst du eine Zufallszahl, die die Kugel angibt. Diese kann von 1-42 oder von 0 - 41 gehen - ist prinzipiell egal.
Dann hast Du die kugel ermittelt, indem Du einfach den Inhalt aus dem Array an der entsprechenden Position ausliest.
Da die Kugel nun aus dem Spiel ist, musst Du diese entfernen. Also stecken wir die letzte Kugel einfach an diese Stelle. Und nun haben wir eine Kugel weniger.
Also wird bei der zweiten Kugel nun eine Zahl von 1 - 41 ermittelt.

Ist also relativ einfach und entspricht zumindest der Lotto Ziehung wie wir diese in Deutschland haben. Da werden halt die Kugeln in eine Maschine gesteckt wo sie herum gewirbelt werden und dann wird eine Kugel entnommen. Danach ist halt eine Kugel weniger in der Maschine und von den verbliebenen Kugeln wird nun wieder eine entnommen. Und das so lange, bis man die gewünschten Kugeln hat.
 
Habe mal ein Lottospiel in der Schule programmiert.

Java:
package lotto.fachklassen;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class LottoLogik {

   private LottoLogik () {
     //verstecke Konstruktor, da dies eine reine Hilfsklasse ist.
   }
 
 
   /**
    * Diese Methode erzeugt ein Array mit 6 Zufallszahlen aus dem Bereich 1 - 49.
    *
    * @return Array mit 6 Zufallszahlen aus dem Bereich 1 - 49.
    */
   public static int[] generiereLottozahlen() {       
     int[] zahlen = new int[49]; // 49 Lottozahlen, zunächst alle = 0
     //Nun initialisiere den Wert der Zellen mit dem Index
     for (int i=0; i<49; i++) zahlen[i] = i+1; //
    // Ziehung von 6 aus 49
    int h, z;
    for (int i=0; i<6; i++) {
    z = (int) (Math.random()*(49-i)); // Zufallszahl aus Bereich 0 bis 48-i
    h = zahlen[z];
    zahlen[z] = zahlen[48-i];
    zahlen[48-i] = h; // Zahlen an den Plätzen z und 48-i werden getauscht.
    }
    //Mit diesem Algorithmus können keine doppelten Werte vorkommen.
    //Der Trick ist, das man den Index verwendet für die Ermittlung der Zufallszahl und nicht die Zahl selbst.
    //Hierzu wird der Wert im Array des gezogenen Index ausgetauscht mit dem Wert aus dem Index des letzten Feldes
    //das noch an der Ziehung teilgenommen hat. Dieses letzte Feld nimmt in der nächsten Ziehung nicht mehr teil,
    //da der Bereich der Zufallszahlen um 1 reduziert wurde.
   
   
    //jetzt fehlt noch die Sortierung
    //zunächst mal die nach hinten sortierten Zahlen in ein neues Array kopieren
    int[] ergebnis = Arrays.copyOfRange(zahlen, 43, 49);
    //nun dieses Array sortieren
    Arrays.sort(ergebnis);
    //sortiertes ergebnis zurückliefern
    return ergebnis;
   }
 
   
   /**
    * Diese Methode liefert die übereinstimmenden Zahlen beider Teilmengen zurück.
    * Entspricht der Schnittmenge beider Arrays.
    *
    * @param tippSet Menge stellt Tipp dar.
    * @param ziehung Menge stellt gezogene Zahlen dar.
    * @return array mit übereinstimmenden Zahlen
    */
   public static Set<Integer> berechneTrefferListe(Set<Integer> tippSet, int[] ziehung) {
     Set<Integer> treffer = new HashSet<Integer>();
     for (int i=0; i < ziehung.length; i++) {
       for (int tipp : tippSet) {
         if (ziehung[i] == tipp) {
           treffer.add(ziehung[i]);
         }
       }
     }
     return treffer;
   }
}




Bei Bedarf kann ich auch das ganze Projekt hochladen.
Ist mit UI umgesetzt.
 

javastudent25

Bekanntes Mitglied
Ok, Konrad ich habe in der Zwischenzeit mal an Aufgabe a gebastelt.
Aber irgendwie schaff ich das nicht mal irgendwie.
Der Code müsste so ein wenig übersichtlicher sein..
Nach der 1. Zahl kommen ein Haufen gleiche Zahlen

Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Random;

public class eugen {

    public static void main(String[] args) {
        zahlenAusgeben(erzeugeZahlenArray());
    }

    public static void zahlenAusgeben(int[] x) {     
        int[] zufallsZahlen = x;
        Arrays.sort(zufallsZahlen);
        for (int i = 0; i < zufallsZahlen.length; i++) {
            System.out.print(zufallsZahlen[i] + " ");
        }
    }

    public static int[] erzeugeZahlenArray() {     
        int y = 0;
        int zaehler=0;
        int[] zufallsZahlen = {0, 0, 0, 0, 0, 0, 0};
        Random rand = new Random();
        int num;

        while(zaehler != 6){         
            num = rand.nextInt(42) + 1;
            for (y = 0; y < (zufallsZahlen.length-1); y++) {
                if(zufallsZahlen[y] != num){
                zufallsZahlen[zaehler] = num;
                }
                zaehler++;
            }         
        }
        erzeugeGlueckszahl(zufallsZahlen, rand);
        return zufallsZahlen;
    }

    public static void erzeugeGlueckszahl(int[] x, Random z) { 
        int a;
        Random rand = z;
        int[] zufallsZahlen = x;     
        a = rand.nextInt(6) + 1;
        zufallsZahlen[6] = a;
    }
}
 
Zuletzt bearbeitet von einem Moderator:
K

kneitzel

Gast
Deine Schleife zur Prüfung, ob die Zahl schon vorhanden ist, macht nicht das, was sie soll. Spiel diese Schleife einmal in Gedanken durch.
 

javastudent25

Bekanntes Mitglied
Ich muss es mir morgen nochmals anschauen, ich komme nicht drauf, was mein Fehler ist..
Irgendwie habe ich heute ein Brett vor dem Kopf..
Wenn ich halb krank bin, sollte ich glaub einfach nicht aus Langeweile programmieren.. ;)

Aber die beiden Varianten von Konrad muss ich schon noch irgendwie herbringen
Mal sehen..

Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Random;

public class eugen {

    public static void main(String[] args) {

        zahlenAusgeben(erzeugeZahlenArray());

    }

    public static void zahlenAusgeben(int[] x) {
       
        int[] zufallsZahlen = x;
        Arrays.sort(zufallsZahlen);
        for (int i = 0; i < zufallsZahlen.length; i++) {
            System.out.print(zufallsZahlen[i] + " ");
        }

    }

    public static int[] erzeugeZahlenArray() {
       
        int y = 0;
        int zaehler=0;
        int[] zufallsZahlen = {0, 0, 0, 0, 0, 0, 0};
        Random rand = new Random();
        int num=0;
        int a=0;

        while(zaehler !=  6){
           
                num = rand.nextInt(42) + 1;
                       
            for (y = 0; y < (zufallsZahlen.length-1); y++) {
                if((num - zufallsZahlen[y]) == 0){
                a=1;
                }
                if(a==1){
                    zufallsZahlen[zaehler] = num;
                    a=0;
                    zaehler++;
                }
            }
           
           
        }
        erzeugeGlueckszahl(zufallsZahlen, rand);
        return zufallsZahlen;

    }

    public static void erzeugeGlueckszahl(int[] x, Random z) {
   
        int a;
        Random rand = z;
        int[] zufallsZahlen = x;
       
        a = rand.nextInt(6) + 1;
        zufallsZahlen[6] = a;

    }

}
 
Hi,
ich hab mir zwar die ganzen Codes nicht angesehen, aber spontan würde ich folgendes vorschlagen:

Speichere doch jede Zufallszahl nacheinander in ein Array. Jede neue Zahl wird - bevor sie eingespeichert wird - mit allen bisherigen Zahlen verglichen. Sobald eine Übereinstimmung vorliegt wird die Zahl sofort verworfen und es geht wieder zur Ziehung einer neuen Zahl.


Java:
public class Zufallszahlen {
    static Random rand = new Random();
 
    //Methode für die Ziehung
    static int erzeugeZahl() {
        int zahl = rand.nextInt(48)+1;
        return zahl;
    }
 
    public static void main(String[] args) {
        int lottozahlen [] = new int [6];
     
        //äußere Schleife --> hier 6 Durchläufe für 6 Zahlen
        meinLabel: for(int i = 0; i < lottozahlen.length; i++) {
            int zwischenspeicher = erzeugeZahl();
         
            //innere Schleife vergleicht neue Zahl mit breits gezogenen Zahlen
            for(int k = 0; k <= i; k++) {
                if(zwischenspeicher == lottozahlen[k])
                    continue meinLabel; //Abbruch bzw Zahl wird verworfen
             
                lottozahlen[i] = zwischenspeicher;
            }
        }
     
        for (int j: lottozahlen) {
            System.out.println(j);
        }
    }
}


Bin selber erst seit kurzem am Java lernen, deswegen ist das bestimmt kein schöner/sauberer objektorientierter Ansatz, aber es funzt :)

Grüße
 
Zuletzt bearbeitet:
K

kneitzel

Gast
Erst einmal eine korrekt aussehende Lösung. Ich würde da aber gerne noch ein paar Worte zur Lesbarkeit verlieren:

Also aus meiner Sicht solltest Du Label komplett vergessen! Das macht den Code in meinen Augen extrem unleserlich!

Das wurde bei Dir ja nur notwendig, weil Du nicht mehr die feste Anzahl an Durchgängen hast sondern nun plötzlich mehrere Durchgänge brauchst. Also wäre die logische Konsequenz, statt for schleife eine while (oder do while) Schleife zu verwenden:
Code:
//äußere Schleife --> hier 6 Durchläufe für 6 Zahlen
      int i = 0; // i sollte besser etwas wie "gezogeneLottozahlen" oder so sein. i sagt ja nichts aus!  
      while(i  < lottozahlen.length){
           int zwischenspeicher = erzeugeZahl();
         
           // Statt innerer Schleife eine Funktion!
           if (!arrayContains(lottozahlen, i, zwischenspeicher))
           {
                lottozahlen[i]= zwischenspeicher;
                i++;
           }
       }
Und die Funktion arrayContains wäre dann einfach:
Code:
public static boolean arrayContains(int[] array, int maxIndex, int value) {
    for (int index=0; index < maxIndex; index++) {
        if (array[index] == value) return true;
    }
    return false;
}

Hinweise:
- Deine innere Schleife prüfte auf <= und hat damit einen Wert zuviel geprüft.
- Diese Version ist deutlich lesbarer. Alleine schon, dass eine Verschachtelung weniger da ist, ist dies so deutlich lesbarer. (Die Alternative wäre tatsächlich so ein "continue" oder eben die Einführung einer Hilfsvariable.)

Das nur als kleine Hinweise zur Lesbarkeit Deines Codes.

Konrad
 

nvidia

Bekanntes Mitglied
Das geht mit etwas Nachdenken alles viel einfacher. Was sind Lottozahlen? Lottozahlen sind eine Liste von Zahlen in einem bestimmten Intervall aus denen n Stück zufällig gezogen werden. Wie modelliert man das am einfachsten?

1. Liste mit Zahlen von 1-49 generieren (per Stream oder For-Schleife)
2. Liste mischen
3. Die ersten 6 Zahlen auslesen und sortiert ausgeben


Java:
public class Lotto {
    public static void main (String ... args){
        //1. Lottozahlen von 1-49 generieren
        List<Integer> lottozahlen = IntStream.range(1, 50).boxed().collect(Collectors.toList());
        //2. Liste mischen
        Collections.shuffle(lottozahlen);
        //3.Die ersten 6 Zahlen auslesen
        List<Integer> ziehung = lottozahlen.subList(0, 6);
        // und Sortieren
        Collections.sort(ziehung);
        System.out.print(ziehung);
    }
}
 
K

kneitzel

Gast
Das erinnert mich an die Zeit, in der ich in einigen MSDN Foren aktiv wa. Im c# Bereich war jemand aktiv, der bei reinen Hausaufgaben-Fragen immer versuchte, so eine Antwort zu bringen. 100% korrekt und es ist klar, dass der Lehrer die Aufgabe nicht als erfüllt ansah und wo auch klar war, dass es nicht vom Schüler gekommen ist :)
 

Schwupsi

Aktives Mitglied
Habe auch ein Lotto Programm geschrieben vor paar Monaten zur Übung.
Sieht ungefähr so aus:

Die Box quasi mit Kugeln von 1-49 füllen

Java:
  public static void initZahlen(){
     
     for(int i = 1; i<=49; i++)
       getLottozahlen().add(i);
     //   System.out.println("Array gefüllt!");
   }

Die Zahlenziehung und das Entfernen bereits vorgekommener Zahlen aus der "Box"

Java:
    public void Ziehung(){
       
        Random random = new Random();
        int random_number;
        setListSize(49);
       
        for(int i = 0; i<ziehung.length; i++){
           
            random_number = random.nextInt(list_size);
            //ziehung[i] = LottoZahlen.Lottozahlen.get((int)((Math.random()*list_size)+1));
            ziehung[i] = LottoZahlen.getLottozahlen().get(random_number);
            LottoZahlen.getLottozahlen().remove(random_number);
            list_size--;
        }
       
    }
 

JStein52

Top Contributor
Spontan hätte ich ja auch eine Lösung mit einer Liste von Zahlen vorgeschlagen die am Anfang mit den Zahlen von 1 - 49 gefüllt wird. Dann wird gewürfelt und die gewürfelte Zahl wird aus der Liste entfernt undf als Ergebnis gemerkt.
Aber der Einzeiler von @thecain ist echt der Hit !
 

Thorwine

Mitglied
Bin ja auch anfangender Umsteiger oder umsteigender Anfaenger in Java, wie man's nimmt. Hab hier grad ein Lottozahlen Projekt aus einem Buch durchgearbeitet, der Erguss kommt also nicht von mir, sondern aus dem Buch "Java fuer Kids". Auch wenn ich dem "Kids" Alter schon etwas entwachsen bin, kann ich die Lektuere sehr empfehlen!

Java:
public class Lotto {

    public static void main(String[] args) {
        // Konstanten
        final int ANZAHL = 6;
        final int MAX = 49;
        // Lottozahlen Array
        int[] lottozahl = new int[MAX + 1];
        // Zufallszahl
        int zufall = 0;

        // Alle Werte im Array auf 0 setzen (noch nicht gezogen)
        for (int count = 1; count < lottozahl.length; count++)
            lottozahl[count] = 0;

        // Sechs Zahlen "ziehen"
        for (int count = 1; count <= ANZAHL; count++) {
          
            // noch nicht verwendete Zufallszahl suchen
            do {
                zufall = (int) (Math.random() * MAX) + 1;
            } while (lottozahl[zufall] == 1);

            // benutzte Zahl als gezogen markieren
            lottozahl[zufall] = 1;
          
            // Ausgabe
            System.out.println(count + ". Ziehung: " + zufall);
        }
    }
}
 
K

kneitzel

Gast
Also kleines Feedback zu Deinem Programm Thorwine:
a) Namensgebung der Variablen: Sieht schon recht gut aus. lottozahl ist etwas unschön. In dem Array ist ja nicht eine lottozahl sondern das ist gezogeneLottozahlen oder so. Ebenso zufall - das ist ja eine zufallszahl. Aber schon eine super Namenswahl.
b) Typenwahl. Ein Array, das nur MAX element speichern soll, sollte auch nur MAX groß sein. Ansonsten muss man den Index immer -1 nehmen oder so. Desweiteren: Wenn Du nur 0/1 als Werte hast, dann ist int der falsche Typ. Da ist boolean ja deutlich besser mit true/false.
 

Thorwine

Mitglied
Korrigierte Fassung:

Java:
public class Lotto {

    public static void main(String[] args) {
        // Konstanten
        final int ANZAHL = 6;
        final int MAX = 49;
        // Lottozahlen Array
        boolean[] gezogeneLottozahlen = new boolean[MAX];
        // Zufallszahl
        int zufallszahl = 0;

        // Alle Werte im Array auf 0 setzen (noch nicht gezogen)
        for (int count = 0; count < gezogeneLottozahlen.length; count++)
            gezogeneLottozahlen[count] = false;

        // Sechs Zahlen "ziehen"
        for (int count = 1; count <= ANZAHL; count++) {

            // Neue Zufallszahl suchen...
            do {
                zufallszahl = (int) (Math.random() * MAX) + 1;
            }
            while (gezogeneLottozahlen[zufallszahl] == true);

            // benutzte Zahl als gezogen markieren
            gezogeneLottozahlen[zufallszahl] = true;

            // Ausgabe
            System.out.println(count + ". Ziehung: " + zufallszahl);
        }
    }
}
 
K

kneitzel

Gast
Da hast Du jetzt aber einen Punkt übersehen. Wenn der MAX Wert gezogen wird, dann bekommst Du eine ArrayOutOfBoundException.
Die Zufallszahl geht von 1 - 49
Dein Array gezogeneLottozahlen geht von 0 - 48
Das musst Du bei Zugriffen beachten. Wenn Zufallszahl 1 ist, willst Du ja in das erste Feld schreiben. Bzw. das erste Feld prüfen. Und das ist Feld 0.
Also müsstest Du diese Zugriffe auch noch anpassen.
 
X

Xyz1

Gast
Wieso denn Counting Sort? Wieso nicht:
Liste mischen,
2 Listen,
Set,
n Folgen, wobei in (n-1). keine doppelten vorkommen?
Nur, um ein paar Beispiele zu nennen.
Java:
        int[] intArr = new int[6]; // 6 bitte nicht ändern :-)
        a: while (true) {
            for (int i = 0; i < intArr.length; i++) {
                intArr[i] = (int) func1(1, 49);
            }
            for (int i = 0; i < intArr.length - 1; i++) {
                for (int j = i + 1; j < intArr.length; j++) {
                    if (intArr[i] == intArr[j]) {
                        continue a;
                    }
                }
            }
            break a;
        }
        System.out.println(Arrays.toString(intArr));
Meine Funktion func1 sieht bei mir so aus:
Java:
    private static float func1(int f, int t) {
        return (float) (Math.random() * (t - f + 1) + f);
    }
Ohnehin braucht random() nur einmal Nanotime.

Btw. Euer nicht reicher Text-Editor ist echt mies für die Augen.
 

Thorwine

Mitglied
Aehm, dann geh ich bei der Pruefung und Zuweisung der Felder im Array einfach eins runter. Ich hoffe, das ist jetzt nicht gepfuscht. Funktionieren tut's so, auch mit den Ziehungen der 1 und der 49. Diese werden jetzt in Feld 0 und Feld 48 geschrieben.

Java:
public class Lotto {

    public static void main(String[] args) {
        // Konstanten
        final int ANZAHL = 6;
        final int MAX = 49;
        // Lottozahlen Array
        boolean[] gezogeneLottozahlen = new boolean[MAX];
        // Zufallszahl
        int zufallszahl = 0;

        // Alle Werte im Array auf 0 setzen (noch nicht gezogen)
        for (int count = 0; count < gezogeneLottozahlen.length; count++)
            gezogeneLottozahlen[count] = false;

        // Sechs Zahlen "ziehen"
        for (int count = 1; count <= ANZAHL; count++) {

            // Neue Zufallszahl suchen...
            do {
                zufallszahl = (int) (Math.random() * MAX) + 1;
            }
            while (gezogeneLottozahlen[zufallszahl-1] == true);

            // benutzte Zahl als gezogen markieren
            gezogeneLottozahlen[zufallszahl-1] = true;

            // Ausgabe
            System.out.println(count + ". Ziehung: " + zufallszahl);
        }
    }
}
 

thecain

Top Contributor
Nur, um ein paar Beispiele zu nennen.
Java:
        int[] intArr = new int[6]; // 6 bitte nicht ändern :-)
        a: while (true) {
            for (int i = 0; i < intArr.length; i++) {
                intArr[i] = (int) func1(1, 49);
            }
            for (int i = 0; i < intArr.length - 1; i++) {
                for (int j = i + 1; j < intArr.length; j++) {
                    if (intArr[i] == intArr[j]) {
                        continue a;
                    }
                }
            }
            break a;
        }
        System.out.println(Arrays.toString(intArr));

Btw. Euer nicht reicher Text-Editor ist echt mies für die Augen.

Dein code ist echt mies für die Augen. "jump to", while(true).

Mir ist egal wie andere ihren Code schreiben, aber es dann Anfängern so zu empfehlen... Bitte nicht.
 
X

Xyz1

Gast
Dein code ist echt mies für die Augen. "jump to", while(true).

Mir ist egal wie andere ihren Code schreiben, aber es dann Anfängern so zu empfehlen... Bitte nicht.

Die besten Kommentare sind keine Kommentare, ich mag das von Thorwine nicht mal lesen, weil es einfach überflüssig ist, jede Zeile zu kommentieren.

Zu dem Rest: Ich presse da kein boolean rein, zu unübersichtlich. for (;;) { wäre noch eine Alternative.

Wählt man n zu groß, hält das Programm leider nicht an. *heul schluchz flenn*
 
K

kneitzel

Gast
@Thorwine: Super! Genau so meinte ich es! Jetzt hätte ich an Deinem Code keine Auffälligkeiten, die ich anders schreiben würde.

@DerWissende: Ich habe echt Probleme Deine Aussage zu verstehen. Der Code selbst ist aber absolut unleserlich und nach meinem Verständnis schlicht schrott:
- Die Nutzung von Label in Java ist etwas, das in meinen Augen jeden Entwickler direkt disqualifiziert. Ich sehe für so einen Spagetticode keine Veranlassung und das ist auch bei fremden Code für mich nicht diskutabel.
- Variablennamen vernünftig wählen, ist hier im Thread oft genug angesprochen worden.
- Dein Code ist extrem verwirrend - Du hast eine Endlosschleife gebaut, dabei wird die Schleife maximal einmal komplett durchlaufen (Du magst mehrfach hoch springen aber sonst?)
- Wenn nur eine Lottozahl doppelt ist, dann fängst Du von vorne an und ermittelst 6 neue Lottozahlen. Vom Algorithmus her ist das alles andere als gut.
- Die Verschachtelungstiefe ist schon zu hoch. Wenn so ein Algorithmus, dann doch bitte mit Unterteilung in Funktionen. Immer noch ganz mangelhaft, aber besser wäre:
Code:
int[] lottoZahlen;
do {
  lottoZahlen = createRandomIntArray(6, 1, 49);
} while (containsDoubleValues(lottoZahlen));

// ...

public static int[] createRandomIntArray(int size, int min, int max) {
  int[] result = new int[size];
  for (int index = 0; index<size; index++)
    result[index] = generateRandomNumber(min, max);
  return result;
}

public static int generateRandomNumber(int min, int max) {
  return (int) (Math.random()*(max - min +1) + min);
}

public static boolean containsDoubleValues(int[] array) {
  for (int lowIndex = 0; lowIndex < array.length-1; lowIndex++) {
    for (int highIndex = lowIndex+1; highIndex < array.length; highIndex++) {
      if (array[lowIndex] == array[highIndex])
        return true;
    }
  }
  return false;
}
Das nur um die Unterteilung zu zeigen. Die Funktionen am Ende sind weniger optimiert. Der Algorithmus ist jetzt aber direkt zu verstehen.
 
K

kneitzel

Gast
Also dass die Kommentare bei Thorwine überflüssig sind, da der Code selbst erklärend ist, ist richtig. Hätte man so sagen können.

Aber ich verstehe nicht, was Du meintest, beitragen zu müssen. Eine gute Lösung braucht kein "Liste Mischen" und keine 2 Listen und auch kein Set. Hättest Du den Thread gelesen, dann hättest Du eine gute Lösung gesehen.

Und was "blöde Lösungen" angeht - da sollten wir einmal genau überlegen, was denn eine blöde Lösung ausmacht. Die Algorithmen, die hier von diversen Anfängern beigesteuert wurden, würde ich nicht als solche bezeichnen. Und Hinweise zu Clean Code sind auf jeden Fall sinnvoll. Aber das werde ich jetzt nicht weiter erläutern, denn die Diskussion / Auseinandersetzung mit Dir ist für mich an dieser Stelle vorbei. Mich würde zwar prinzipiell noch interessieren, was Du meintest beitragen zu können / müssen, aber andererseits ist mir dazu meine Zeit zu schade.

Ich wünsche noch einen schönen Abend.
 

Thorwine

Mitglied
Die besten Kommentare sind keine Kommentare, ich mag das von Thorwine nicht mal lesen, weil es einfach überflüssig ist, jede Zeile zu kommentieren.
Sorry, bin noch nicht so der Profi und die Kommentare sind fuer mich persoenlich noch sehr wichtig als Gedankenstuetze und um die Sache in ein paar Wochen auch noch nachvollziehen zu koennen. Aber ich kann die Kommentare in meinen Posts hier im Forum ja zukuenftig vor dem Posten rausloeschen, das sollte kein Problem sein. Dennoch bin ich sehr froh, dass zB @kneitzel meinen Code liest und mir gute Tipps gibt. Des Weiteren hab ich gelernt, dass Kommentare durchaus gewuenscht sind. Bei uns in der Firma bekommen die Entwickler boese auf die Finger, wenn sie ihren Code nicht kommentieren.
 

Flown

Administrator
Mitarbeiter
@Thorwine bitte behalte dir deinen Stil bei. Wenn es dir eine Stütze ist Gedanken aufzuschreiben und Schritte zu kommentieren, dann soll es so sein (vl. hilft es anderen Anfängern genau so).

An alle anderen: Bleibt sachlich! Keiner muss hier beweisen, wer den besseren/kürzesten Code schreiben kann. Klar im Vordergrund sollte stehen:
- Den Fragenden helfen
- Code anzusehen und Verbesserungsvorschläge bieten!
- Feedback geben und auch erhalten können (und damit auch leben können)!
- Klare Fakten bieten und keinen Sarkasmus/etc.
- Alles klar verständlich ausformulieren und keine Stichworte bieten
- Code den man bereitstellt auch in Javadoc oder außerhalb erklären und kommentieren

PS: Wenn das Thema hier weiter ausartet, wird es geschlossen
 
Zuletzt bearbeitet:
K

kneitzel

Gast
@Thorwine: Also Du musst die Kommentare nicht löschen! Das ist vollkommen in Ordnung aus meiner Sicht! Daher gab es diesen Punkt von meiner Seite aus nicht! Nur eben ist dieser Punkt, der von dritter Seite angebracht wurde, durchaus legitim.

Die Idee beim Clean Code ist aber, dass der Code selbst so geschrieben ist, dass er gut lesbar ist. Dann sind die Kommentare nicht mehr notwendig. Und die Probleme durch Kommentare werden vermieden. Probleme gibt es einige:
a) Ungenaue Kommentare - Wenn man einen Kommentar schreibt, dann ist der Kommentar evtl. zu ungenau. Dann steht im Kommentar: "Auto wird lackiert" und der Code klebt die Scheiben ab und lackiert dann das Auto. Kleinigkeit, aber man erkennt die Ungenauigkeit.
b) Mehrfache Änderungen - es wird immer versucht, doppelten Code zu vermeiden, damit man bei Änderungen nur eine Stelle ändern muss. Und durch die Kommentare wird es wieder doppelt: Wenn ich Auto Lackieren ändere, dann ändere ich den Code (z.B. Scheiben werden noch abgeklebt) aber in den Kommentaren vergesse ich es evtl. oder ich muss es eben noch an einer zweiten Stelle ändern.

Daher ist nach aktuellen Überlegungen es tatsächlich so, dass Kommentare eher als problematisch anzusehen sind.

Ausnahme hier sind javadoc Dokumente. Alles, was public ist, muss dokumentiert werden. Hintergrund hier ist, dass diese Kommentare in der Dokumentation wieder auftauchen (Also ähnlich wie die Dokumentation des Frameworks) bzw. bei uns in der Firma: Visual Studio zeigt die Dokumentation im Editor mit an bei IntelliSense. Also wenn ich someObject.SomeFunction( schreibe, dann zeigt mir Visual Studio auch ein Popup mit Beschreibung der Funktion und der Dokumentation der Parameter.

Aber ja - früher war es bezüglich Kommentare wirklich anders. Das kenne ich auch noch. Aber bei CleanCode sind fast alle Kommentare überflüssig. Dafür gibt es sehr viele Regeln, die dann auch Verschachtelungstiefe und Länge einer Funktion eingrenzen. Und alles sollte in einer Funktion auf einer Ebene sein und so.... aber das ist etwas, dass am Anfang einfach zu viel ist. Also immer nur auf eine Sache konzentrieren und dabei dann in erster Linie die Dinge mitnehmen, die nicht so kompliziert sind und auch viel helfen. Sinnvolle Variablennamen sind da z.B. wichtig.

Daher am Ende ein ganz wichtiger Punkt: Im Forum werden Threads manchmal etwas "gehijackt". Dann "kloppen" wir uns mal etwas. Dann legt man eine Aussage auf die Goldwaage und fragt dann nach und dann klären wir evtl. untereinander eine Fragestellung, die für den Thread Ersteller nicht wichtig ist und die ihn nur verwirrt. Da bitte ich um etwas Verständnis.
==> Lass Deine Kommentare also in Zukunft ruhig im Code drin wenn Du Code postest!

Wenn Dich der Punkt mit den Kommentaren interessiert, dann kann ich Dir aber gerne anbieten, dass ich Deinen Code noch einmal etwas umschreibe, so dass Du dann erkennst, dass die Kommentare unnötig werden könnten.
 
X

Xyz1

Gast
Nagut, dann sorge ich mal dafür, das hier geschlossen wird.

kneitzel, versteht etwas komplizierte Algorithmen nicht. Punkt. Fakt. :) :

- Die Nutzung von Label in Java ist etwas, das in meinen Augen jeden Entwickler direkt disqualifiziert. Ich sehe für so einen Spagetticode keine Veranlassung und das ist auch bei fremden Code für mich nicht diskutabel.

Die Hälfte der Entwickler von Oracle sind disqualifiziert. Spagetti entsteht, wenn man auch noch einen Bool oder do-while-true verwendet.

- Variablennamen vernünftig wählen, ist hier im Thread oft genug angesprochen worden.

Profi Abkürzungen verstehen liegt nicht jedem.

- Dein Code ist extrem verwirrend - Du hast eine Endlosschleife gebaut, dabei wird die Schleife maximal einmal komplett durchlaufen (Du magst mehrfach hoch springen aber sonst?)

Beweis für Korrektheit und Anhaltbarkeit bitte, den du nicht erbringen kannst. q.e.d.

- Wenn nur eine Lottozahl doppelt ist, dann fängst Du von vorne an und ermittelst 6 neue Lottozahlen. Vom Algorithmus her ist das alles andere als gut.

Von Performance / Mikrooptimierung sprach hier keiner, sonst würde es die Hälfte der Lösungen nicht geben, und ihr würdet eine Set verwenden, wegen des Speicherplatzverhaltens.

- Die Verschachtelungstiefe ist schon zu hoch. Wenn so ein Algorithmus, dann doch bitte mit Unterteilung in Funktionen. Immer noch ganz mangelhaft, aber besser wäre:

Vor 40 Jahren wurde dieser Quatsch noch gelehrt, nicht mehr Zeilen als eine Bildschirmseite, mittlerweile ist das überholt, im Übrigen ist es nicht mal eine Bildschirmseite, die du aufteilen willst.

[-] Der Algorithmus ist jetzt aber direkt zu verstehen.

Nicht mehr zu verstehen, meinst du eher.

Andere Beiträge will ich mir jetzt gar nicht rauspicken.

@ TO/TE : Du kannst das zwar so schreiben, aber das ist - zunächst alle Vorkommen zählen - die Hälfte des bereits erwähntem CountingSorts. Auch ist es dir überlassen, jede Zeile zu kommentieren, als Gedankenstütze, um es nach X Jahren noch zu verstehen - lass mich aber bitte damit in Ruhe, denn mit Anfängern will ich nix zu tun haben. :)

*Thema schließung droht*
 
K

kneitzel

Gast
Für den Fall, dass jemand interessiert ist, aus welchen Quellen ich mein Wissen beziehe:
- http://www.amazon.de/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882
- http://www.clean-code-developer.de

Nicht, dass hier der Eindruck entsteht, ich würde irgendwelche uralten Dinge umsetzen wollen. (Wobei das Buch von 2008 ist. Das kann schon uralt sein.) Softwareentwicklung ist ein sehr dynamisches Umfeld und regelmäßig werden neue Kühe durch das Dorf getrieben. Derzeit ist es noch continuous delivery aber es gab schon viele Kühe. Einiges hat sich durchgesetzt wie Objektorientierte Entwicklung und andere Dinge haben schlicht ihre Nische gefunden und werden von vielen ignoriert.
Oft ist es auch so, dass manche Dinge einfach nicht passen. So setzen wir auf Arbeit kein wirkliches SCRUM ein sondern haben unsere Arbeitsweise an die Anforderungen des Managements angepasst.
So gibt es auch angepasste Coding Guidelines - so hat jemand neulich im FOrum geschrieben, dass sie auf Arbeit sowohl Java als auch C# Code entwickeln und bezüglich Coding Guidelines haben sie sich auf eine Schreibweise geeinigt. Bei den geschweiften Klammern war es dann die "C# Schreibweise". Ist doch ok!

Generell soll jeder so Software entwickeln, wie er es für richtig hält. Ich habe Perl Entwickler kennen gelernt, die sehr komplexe Algorithmen in ein oder zwei Zeilen gepackt haben. Hat auch gewisse Vorteile wie Jobsicherung - der Typ war so ohne weiteres nicht ersetzbar solange nicht auf die Wartung aller seiner Scripte verzichtet wird. Aber er hat von sich nie behauptet, dass sein Code gut leserlich gewesen wäre. :)

Und die Tatsache, dass es in gewissen Bereichen kaum sinnvolle Alternativen gibt oder dort "Clean Code" uninteressant ist, ändert nichts an den Grundlagen von Clean Code und auch an der Wichtigkeit. Wer das nicht kennt und nicht kennen will: Ist ok, habe ich kein Problem mit. Aber wer darüber diskutieren will, der sollte es kennen. Wer es nicht kennt, soll sich die Ergebnisse ansehen und dann selbst entscheiden, was er besser findet.
 

JStein52

Top Contributor
Leute was habt ihr denn heute geraucht ? @Thorwine hat doch nur etwas aus dem Buch Java für Kids hier gepostet und dazu ein paar Anmerkungen erhalten. Dass in so einem Codeschnipsel ein paar Kommentare mehr drin sind ist doch logisch. Wahrscheinlich müsste man den Buchtext hierzu sehen der sicher darauf Bezug nimmt. Das Anliegen des TO/TE ist doch schon lange abgehakt und wenn es um die "schönste" Lösung geht hat für mich nach wie vor @thecain den Vogel abgeschossen mit seinem Einzeiler (der noch nicht mal Kommentare benötigt um ihn zu verstehen) ;)

@ TO/TE : Du kannst das zwar so schreiben,
Du musst den Thread mal komplett lesen, thorwine ist nicht der TE
 

javastudent25

Bekanntes Mitglied
ok, ich habe jetzt mal die Zahlen in einem einzigen Array generiert..
ich komme einfach nicht zurecht mit der while und einer for
ich verstehe zwar was ihr meint, aber wenn ich jetzt den array habe, kann ich jetzt zB eine Variable definieren

variable a

dort kann ich jetzt den 1. Index vom array speichern und das ganze array durchgehen und abfragen ob die der aktuelle Index der gespeicherten zahl entspricht, ok.
wenn die Zahlen gleich sind, sage ich ok, generiere dann eine neue Zahl und speichere sie in den aktuellen Index.
Aber gleichzeitig muss ich ja sagen, fang von vorne an mit der for-schleife
sonst gibt er vermutlich die gleiche zahl wie index 1 ein und geht einfach weiter.
dann ist ja index 1 und 3 gleich, könnte ja so sein..

könnte mir vllt jemand mal so wie mein Code bisher ist dafür die 2-3 Zeilen Code hinschreiben, die mir doppelte Zahlen vermeiden? oder zumindest mal die ersten SChritte.
Im komme einfach nicht dahinter..

Java:
import java.io.*;
import java.text.*;
import java.util.*;
import java.lang.String;

public class Lottozahlen {

    public static void main(String[] args) {
        // Dies ist das Array, in das die Zahlen gespeichert werden
        // static String[][] array = new String[500][500];
        Filter filter = new Filter();
        Lotto lotto = new Lotto();
        lotto.getGesamtArray();
      

    }

}

Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Random;

public class Lotto {
  
    private int[] zufallsZahlen = new int[6];
    private int[] gluecksZahl = new int[1];
    private int[] array = new int[zufallsZahlen.length + gluecksZahl.length];

    private void zahlenAusgeben() {
      
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + " ");
        }
    }
  
    private void erzeugeZahlenArray() {
      
        Random rand = new Random();
        for (int a = 0; a < (zufallsZahlen.length); a++) {
            int num = rand.nextInt(42) + 1;
            zufallsZahlen[a] = num;
        }
      
    }
  
    private void erzeugeGlueckszahl() {

        Random random = new Random();
        int zufall = random.nextInt(6) + 1;
        gluecksZahl[0] = zufall;

    }
  
    public void getGesamtArray(){
      
        erzeugeZahlenArray();
        Arrays.sort(zufallsZahlen);
        erzeugeGlueckszahl();
      
        for(int i=0;i<zufallsZahlen.length;i++){
           array[i]=zufallsZahlen[i];
        }
        for(int i=0;i<gluecksZahl.length;i++){
           array[zufallsZahlen.length+i]=gluecksZahl[i];
        }
        zahlenAusgeben();
      
      
    }
}
 
Zuletzt bearbeitet:

Tarrew

Top Contributor
Ich muss gestehen, ich habe mir nicht den ganzen Thread durchgelesen aber wenn ich das richtig verstehe möchtest du ein Array mit Zufallszahlen, dass keine doppelten Einträge enthält.
Wenn du nur mit Arrays arbeiten willst, dann würde sowas klappen:
Java:
    public static void main(String[] args) throws ParseException {
        int[] array = new int[6];
        Random r = new Random();
        int randomNumber;
        for(int i=0; i<array.length; i++){
            do{
                randomNumber = r.nextInt(6) + 1;
            }while(containsValue(array, randomNumber));
            array[i]=randomNumber;
        }
        System.out.println(Arrays.toString(array));
    }
  
    private static boolean containsValue(int[] array, int value){
        for(int i=0; i<array.length; i++){
            if(array[i]==value){
                return true;
            }
        }
        return false;
    }


Ansonsten wäre für die Aufgabe ein Set ganz nützlich, weil es keine doppelten Elemente enthalten kann, aber das hat vermutlich schon jemand vorgeschlagen:
Java:
        Set<Integer> set = new TreeSet<>();
        Random r = new Random();
        do {
            set.add(r.nextInt(42) + 1);
        } while (set.size() != 6);
        System.out.println(set.toString());

#Edit: Wobei ich gerade sehe, dass unter anderem kneitzel schon Code gepostet hat, der genau das macht. Vllt. hab ich dein Problem dann falsch verstanden ;;o
 
Zuletzt bearbeitet:
X

Xyz1

Gast
Und ihr werft mir Spagetticode vor, wenn ich das schon sehe *kotz*
Allein das neue Random Objekt ist unnötig.
Genau wie do while usw.
 
X

Xyz1

Gast
Math.random() ist bereits ein Singleton (über statische innere Klassen Fabrik)
do while ist ein Schlüsselwort mehr, unleserlich und langsam

Muss ich dazu noch mehr schreiben? An meinem Text hätte er noch was
lernen können.
 

Meniskusschaden

Top Contributor
Math.random() ist bereits ein Singleton (über statische innere Klassen Fabrik)
Verstehe immer noch nicht, warum das ein Argument gegen den Komfort eines Random-Objekts sein soll.

do while ist ein Schlüsselwort mehr, unleserlich und langsam
Wenn man die Bedingung am Schleifenende prüfen möchte, braucht man eben etwas, um den Beginn zu kennzeichnen. Das do ist dafür doch sehr geeignet weil es besonders gut lesbar ist. Ist aber müßig, darüber zu diskutieren, denn in Java baut man solche Schleifen eben mit do while. Man kann da schlecht mal eben ein eigenes Schlüsselwort erfinden. Warum sollten do while Schleifen denn langsamer sein, als andere Schleifen?
 
K

kneitzel

Gast
@DerWissende Wäre nett, wenn Du Dich etwas besser verständlich ausdrücken würdest. Im Sugenblick weiss ich einfach nicht, welchen Code Du speziell bemängelst als so unleserlich. Und wenn am Ende geprüft werden soll, dann ist do while die richtige Lösung. Was machst Du denn statt dessen? Doppelten Code? Einmal vor die while schleife und einmal in der Whileschleife? Oder verkomplizierst Du die Bedingung?
Bezüglich random objekt: Ja, das ist etwas, das optimiert werden könnte. Aber ich würde dies anders optimieren als Du: random Objekt erstellen: ja. Aber bitte für Tests mit seed, damit die Tests gleich ablaufen und rekonstruierbar sind. Aber das ist für eine Hausaufgabe in der Schule deutlich zu komplex und ich habe nicht vor, die Gründe hier zu erläutern.

@javaStudent Die Lösung zu allen Problemen ist oft ganz schnell gefunden, wenn man eine komplexe Aufgabe unterteilt. Divide and Conquer - Teile und Hersche. Das bedeutet für mich im Rahmen der Entwicklung zwei Dinge:
a) Unterteilung des Ablaufs in viele kleine Schritte. Denn genau dies vereinfacht vieles in Bezug auf die Lesbarkeit. Du kannst einfach abbrechen und rausspringen wäre z.B. ein Vorteil. Du hast Dinge direkt "kommentiert" - denn es steht ja ein aussagekräftiger Funktionsname vor den meist kleinen Funktionen. Die Funktionen lesen sich einfach, da dort viele aussagekräftige Funktionen aufgerufen werden ...
b) Unterteilung der zu bearbeitenden Menge. Ein Beispiel wäre hier z.B. der QuickSort Algorithmus. Aber wichtig wird dies auch in vielen anderen Bereichen wie z.B. der Parallelisierung von Aufgaben, was bei den heutigen CPUs sehr wichtig wird..

Und es ist recht fatal, hier mit irgendwelchen massiv verschachtelten Schleifen etwas abbilden zu wollen. Das geht, keine Frage, aber dann hast Du einen riesen-Codeblock, in dem Du auf einem Array mit mehreren Operationen hantierst. Das wird recht komplex.

Aber so ein Code ist schreibbar (auch ohne Label :) ):
1. Schleife über das Array
1.1. Arrayelement füllen mit Zufallszahl

2. Schleife über das Array (i=1, i<array.lebgth, i++)
==> Dies ist die äußere Schleife!
2.1. Schleife über Elemente bis (exkluded) ites Element (j=0, j<i, j++)
==> Diese Elemente vergleichen wir jetzt jeweils mit dem i-ten Element
2.1.1. if ites Element == jtes Element
2.1.1.true.1. ites Element = Zufallszahl
2.1.1.true.2. j = -1
==> wird mit j++ am Ende dann 0, d.h. die Schleife 2.1 fängt von vorne an.

Da hat man jetzt das mit der Zufallszahl zwei Mal. Das könnte man jetzt noch umschreiben (Warum? Clean Code interessierte uns doch nicht!):

1. Schleife über das Array (i=0, i<array.lebgth, i++)
==> Dies ist die äußere Schleife! Fängt nun mit 0 an.
1.1. ites Element = Zufallszahl
1.2. Schleife über Elemente bis (exkluded) ites Element (j=0, j<i, j++)
==> Diese Elemente vergleichen wir jetzt jeweils mit dem i-ten Element
1.2.1. if ites Element == jtes Element
1.2.1.true.1. j = i;
==> Die innere Schleife wird beendet
1.2.1.true.2 i = i - 1;
==> Wir wiederholen diesen Schritt der äußeren Schleife noch einmal.

Besser? Nicht wirklich.

Du kannst diesen Pseudocode gerne einmal in Java umsetzen. Zur besonderen Unleserlichkeit empfehle ich das array a zu nennen, so dass da nur a, i und j auftauchen :)

Andere Lösungen gibt es schon im Thread, so dass ich darauf nicht näher eingehen werde.
==> Lösungen bezüglich "Schule": Da habe unter anderem ich aufgezeigt, wie das aussehen könnte.
==> Lösung bezüglich Framework einsetzen: Da nimmt man kein Array sondern ein Set. Richtige Wahl der vorhandenen Datentypen!
==> "Moderne" Lösung: Hier sehe ich den Einzeiler aus dem Thread ganz weit oben, denn er ist lesbar und liefert eine gute Lösung.
 
X

Xyz1

Gast
Math.random() ist bereits ein Singleton (über statische innere Klassen Fabrik)
do while ist ein Schlüsselwort mehr, unleserlich und langsam

... siehe dir diesbezüglich auch Bytecode an, eine Anweisung mehr ...

Zudem ist er auch noch falsch, wenn irgendwann einmal die Anforderung gestellt werden sollte, dass das Zufallszahlenarray auch leer sein könnte.

Alles in Allem, es bleibt Anfängercode, und ihr wollt mir Ver(schlimm)besserungsratschläge geben! :confused:
 

Meniskusschaden

Top Contributor
... siehe dir diesbezüglich auch Bytecode an, eine Anweisung mehr ...
Habe es mir angesehen. Für dieses Beispiel:
Java:
public class DoWhileTest {
    public static void main(String[] args) {
        int i = 0;
        do {
            System.out.println(i++);
        } while (i < 5);
    }
}
bekomme ich folgenden Bytecode:
Code:
public class DoWhileTest {
  public DoWhileTest();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       5: iload_1
       6: iinc          1, 1
       9: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      12: iload_1
      13: iconst_5
      14: if_icmplt     2
      17: return
}

Für dieses Beispiel:
Java:
public class WhileTest {
    public static void main(String[] args) {
        int i = 0;
        while (i < 5) {
            System.out.println(i++);
        }
    }
}

erhalte ich folgenden Bytecode:
Code:
public class WhileTest {
  public WhileTest();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: goto          15
       5: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       8: iload_1
       9: iinc          1, 1
      12: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      15: iload_1
      16: iconst_5
      17: if_icmplt     5
      20: return
}

Ich kann da beim besten Willen keinen Performance-Nachteil der doWhile-Schleife erkennen. Der Bytecode ist sogar kürzer. Die Unterschiede, die es geben mag, wären meines Erachtens ohnehin völlig irrelevant. Das fällt überhaupt nicht in's Gewicht.
Ich verstehe auch nicht, warum dir dieses Performancethema jetzt so wichtig ist. Dun hast weiter oben doch noch geschrieben, dass es nicht um Mikrooptimierung und Performance geht, als an deinem Algorithmus kritisiert wurde, dass er bei einer doppelten Zufallszahl komplett von vorne anfängt (habe nicht geprüft, ob das stimmt). Solange man so großes Optimierungspotential liegen lässt, ist es doch völlig unverhältnismässig, doWhile als vermeintlichen Performancekiller zu umgehen.
 

Meniskusschaden

Top Contributor
Zudem ist er auch noch falsch, wenn irgendwann einmal die Anforderung gestellt werden sollte, dass das Zufallszahlenarray auch leer sein könnte.
Da du jetzt Anforderungsänderungen in's Spiel bringst, noch eine Anmerkung zu deinem Algorithmus. Er garantiert ja nicht, dass er überhaupt terminiert (insofern sind Performancevergleiche ohnehin müßig). Habe ihn spaßeshalber mal für eine Ziehung 36 aus 42 aufgerufen. Das hat schon ein paar Minuten gedauert, bis er fertig war.
 
X

Xyz1

Gast
Er terminiert für höhere n nicht, weil Zufallszahlen nicht wirklich Zufallszahlen sind, müsste man schon das Hintergrundrauschen des Universums beobachten dafür.
 
K

kneitzel

Gast
Also wenn, dann bitte sauber bleiben: Natürlich terminiert er. Wenn ich n Zufallszahlen aus n möglichen ziehe, dann terminiert er, sobald er halt wirklich n "richtige" erwischt hat. Die Wahrscheinlichkeit kann man ausrechnen. Ebenso kann man die Wahrscheinlichkeit auch für x (mit x<n) unterschiedlichen Zahlen aus n berechnen.

Und ob nun ein Befehl mehr bei raus kommt oder nicht, ist relativ egal. Es wird teilweise extrem viel Performance verschenkt nur um Vorteile wie Aspekte oder so zu haben.... Und wer clean-code-developer.de kennt, der wird bei so Optimierungen ehh die Hände über den Kopf zusammen schlagen :)
 

Ähnliche Java Themen

Neue Themen


Oben