Thorsten F.: 16 verschiedene Zufallszahlen

Hallo Leute,
habe diesen Code

n = new Array();
for(i=1;i<=16;i++)
{
 var random = Math.random();
 var teiler = 1/16;
 var not_round = random / teiler;
 var round = Math.round(not_round);
 if(round==n[i])
 {
  alert("SCHON IM ARRAY VORHANDEN DRIN");
  i--;
 }
 n.push(round);
}

, aber die ausgegebenen Zufallszahlen sind nicht alle verschieden. Es gibt teileweise also gleiche Zahlen im Array.

Das mit der IF-Schleife passt also nicht so ganz. Wäre für Hilfe dankbar.

Gruß,
Thorsten F.

  1. n = new Array();
    for(i=1;i<=16;i++)
    {
    var random = Math.random();
    var teiler = 1/16;
    var not_round = random / teiler;
    var round = Math.round(not_round);
    if(round==n[i])
    {
      alert("SCHON IM ARRAY VORHANDEN DRIN");
      i--;
    }
    n.push(round);
    }

    , aber die ausgegebenen Zufallszahlen sind nicht alle verschieden. Es gibt teileweise also gleiche Zahlen im Array.

    Du kannst ein Objekt nutzen.

    var n = new Array();
    var check = new Object();

    while(n.length < 16)
    {
        var random = Math.round( Math.random() * 16);
        if( !check[random] )
        {
        n.push(random );
        check[random] = true;
        }
    }
    alert(n);

    Das sieht eher so aus, als ob du ein Array mischen willst, da gibt es bessere Möglichkeiten.

    Struppi.

    1. Hallo Struppi,

      Das sieht eher so aus, als ob du ein Array mischen willst, da gibt es bessere Möglichkeiten.

      Meinst du in etwa so?

        
      var myArray = new Array ('null', 'eins', 'zwei', 'drei', 'vier',  
                              'fünf', 'sechs', 'sieben', 'acht', 'neun',  
                              'zehn', 'elf', 'zwölf', 'dreizehn',  
                              'vierzehn', 'fünfzehn', 'sechzehn');  
        
      var mix = new Array();  
      var max = myArray.length;  
        
      function rollDice () {  
        var num = -1;  
        do {  
          num = parseInt(Math.random()* myArray.length);  
        } while((isNaN(num))||(num<0));  
        return num;  
      }  
        
      function mixIt (){  
        for (var i=0; i<max; i++) {  
          num = rollDice();  
          myArray1 = myArray.slice(0,num);  
          myArray2 = myArray.slice(num);  
          mix[i] = myArray2.shift();  
          myArray = myArray2.concat(myArray1);  
        }  
        myArray = mix;  
        return mix;  
      }  
        
      function writeIt () {  
         for (var i=0; i<30; i++) {  
           document.write(mixIt().join('<span style="color:red">&nbsp;|&nbsp;</span>')+'<br>');  
         }  
      }  
        
      writeIt();  
      
      

      Da wird einfach ein Array-Member an zufälliger Stelle für das Mix-Array ausgewählt und gleichzeitig aus dem Ursprungsarray entfernt. Im nächsten Durchgang wird dann nur aus den verbliebenen Membern des Ursprungs-Arrays ausgewählt und auch dieses entfernt und usw. usf., bis das Ursprungsarray schließlich leer ist. Zum Schluss wird das Ursprungsarry mit seiner gemischten Kopie wieder befüllt, so dass es für die nächste Mischung wieder bereit steht.

      Durch den Verzicht auf verschachtelte Schleifen und Zurücksetzen von Zählern sollte mit dieser Technik jedenfalls auch die CPU geschont werden, was sich bei sehr großen Arrays von mehreren hundert Membern wohl auch in der Berechnungszeit bemerkbar machen dürfte.

      Gruß Gernot

      1. Meinst du in etwa so?

        var myArray = new Array ('null', 'eins', 'zwei', 'drei', 'vier',
                                'fünf', 'sechs', 'sieben', 'acht', 'neun',
                                'zehn', 'elf', 'zwölf', 'dreizehn',
                                'vierzehn', 'fünfzehn', 'sechzehn');

        var mix = new Array();
        var max = myArray.length;

        function rollDice () {
          var num = -1;
          do {
            num = parseInt(Math.random()* myArray.length);
          } while((isNaN(num))||(num<0));
          return num;
        }

        function mixIt (){
          for (var i=0; i<max; i++) {
            num = rollDice();
            myArray1 = myArray.slice(0,num);
            myArray2 = myArray.slice(num);
            mix[i] = myArray2.shift();
            myArray = myArray2.concat(myArray1);
          }
          myArray = mix;
          return mix;
        }

        function writeIt () {
           for (var i=0; i<30; i++) {
             document.write(mixIt().join('<span style="color:red">&nbsp;|&nbsp;</span>')+'<br>');
           }
        }

        writeIt();

          
        Sieht umständlich aus, finde ich.  
          
        Ich würd's so machen:  
        ~~~javascript
          
        var myArray = new Array ('null', 'eins', 'zwei', 'drei', 'vier',  
                                'fünf', 'sechs', 'sieben', 'acht', 'neun',  
                                'zehn', 'elf', 'zwölf', 'dreizehn',  
                                'vierzehn', 'fünfzehn', 'sechzehn');  
          
        mischen(myArray)  
        alert(myArray.join('\n'));  
          
        function mischen(array, anzahl)  
        {  
            if(!anzahl || anzahl < 0) anzahl = 1;  
            while(anzahl--)  
            {  
                 for(var i = 0; i < array.length; i++)  
                 {  
                      var index = parseInt( Math.random() * array.length - 1);  
                      var tmp = array[index];  
                      array[index] = array[i];  
                      array[i] = tmp;  
                 }  
            }  
        }  
        
        

        einfach uhnd schnell.

        Struppi.

        1. Hallo Struppi,

            
          
          > function mischen(array, anzahl)  
          > {  
          >     if(!anzahl || anzahl < 0) anzahl = 1;  
          >     while(anzahl--)  
          >     {  
          >          for(var i = 0; i < array.length; i++)  
          >          {  
          >               var index = parseInt( Math.random() * array.length - 1);  
          >               var tmp = array[index];  
          >               array[index] = array[i];  
          >               array[i] = tmp;  
          >          }  
          >     }  
          > }  
          
          

          Neidlos muss ich eingestehen, dass du auf jeden Fall eine Rechenoperation weniger in deiner For-Schleife hast. Meine Array-Manipulationen verursachen intern wahrscheinlich auch einen bedeutend höheren Rechenaufwand.

          Auf deine while-Schleife und den Parameter anzahl könntest du aber doch auch noch verzichten, oder was versprichst du dir von mehreren Mischdurchläufen, wenn doch in jedem Fall kein einziges der Members unberührt bleibt?

          Ich könnte mir sogar im Gegenteil bei deiner Variante auch noch vorstellen, den Increment in Zweierschritten laufen zu lassen, also i+=2, denn bei jedem deiner Schleifendurchläufe sind ja zwei Array-Members betroffen. Die übersprungenen Members wären dann allerdings nur mit halb so hoher Wahrscheinlichkeit von der Veränderung betroffen wie die nicht-übersprungenen.

          Was meine Würfel-Funktion betrifft; diesen Aufwand habe ich mal vor Zeiten für Netscape 4.7 eingebaut, der die Eigenheit hatte, bei einer einfachen Random-Funktion auch zuweilen ein 'undefined' oder einen negativen Wert zurückzuliefern.

            
          
          > > function rollDice () {  
          > >   var num = -1;  
          > >   do {  
          > >     num = parseInt(Math.random()* myArray.length);  
          > >   } while((isNaN(num))||(num<0));  
          > >   return num;  
          > > }  
          
          

          Gruß Gernot

          1. Neidlos muss ich eingestehen, dass du auf jeden Fall eine Rechenoperation weniger in deiner For-Schleife hast. Meine Array-Manipulationen verursachen intern wahrscheinlich auch einen bedeutend höheren Rechenaufwand.

            Danke :-)

            Auf deine while-Schleife und den Parameter anzahl könntest du aber doch auch noch verzichten, oder was versprichst du dir von mehreren Mischdurchläufen, wenn doch in jedem Fall kein einziges der Members unberührt bleibt?

            Nur ein besseres Gefühl ;-)
            man mischt ja auch von Hand manchmal doch einmal nach.

            Ich könnte mir sogar im Gegenteil bei deiner Variante auch noch vorstellen, den Increment in Zweierschritten laufen zu lassen, also i+=2, denn bei jedem deiner Schleifendurchläufe sind ja zwei Array-Members betroffen. Die übersprungenen Members wären dann allerdings nur mit halb so hoher Wahrscheinlichkeit von der Veränderung betroffen wie die nicht-übersprungenen.

            Wenn man wirklich eine schnellere Methode braucht, aber i.d.R. dürfte die obige Schleife ja schnell genug sein.

            Was meine Würfel-Funktion betrifft; diesen Aufwand habe ich mal vor Zeiten für Netscape 4.7 eingebaut, der die Eigenheit hatte, bei einer einfachen Random-Funktion auch zuweilen ein 'undefined' oder einen negativen Wert zurückzuliefern.

            ich hatte mich schon gewundert, vorstellen kann ich mir das aber nicht, da die random Funktionen schon seit Computer Urzeiten existiert und solche Verrenkungen hab ich nicht mal auf'm C64 oder ZXSprectrum gebraucht.

            Struppi.

  2. Γειά σου, Thorsten!

    n = new Array();

    for(i=1;i<=16;i++)
    {
    var random = Math.random();
    var teiler = 1/16;
    var not_round = random / teiler;
    var round = Math.round(not_round);
    if(round==n[i])
    {
      alert("SCHON IM ARRAY VORHANDEN DRIN");
      i--;
    }
    n.push(round);
    }

    
    >   
    > , aber die ausgegebenen Zufallszahlen sind nicht alle verschieden. Es gibt teileweise also gleiche Zahlen im Array.  
    >   
    > Das mit der IF-Schleife passt also nicht so ganz. Wäre für Hilfe dankbar.  
      
    `if(round==n[i])`{:.language-javascript} prüft nur für einen Wert im Array `n`{:.language-javascript}, ob dieser gleich der Variablen `round`{:.language-javascript} ist. Du möchtest aber alle Werte des Arrays prüfen, d. h. du musst in einer Schleife alle Werte des Arrays durchlaufen und abchecken. Konkret sähe das etwa so aus:  
      
    for(i=0;i<=15;i++) { //Das erste Element eines Arrays hat gewöhnlich den Index 0 (Null). Das Element mit dem Index 15 ist dann das sechzehnte.  
        ...  
        for(j=0;j<=15;j++) {  
            if (n[j]==round) {  
                alert("Wert bereits vorhanden, neuer Durchlauf wird gestartet.");  
                i--;  
                j=16; //Wenn der Wert der Variablen round im Array vorhanden ist, abbrechen und ihn durch einen nuen ersetzen.  
            }  
        }  
        ...  
    }  
      
    Αντίο!  
    [Sven](http://arx.de.tt/) aus [Bonn](http://www.bonn.de/)
    
    -- 
    Ἀεὶ πάντα ῥεῖ.  
      
    Selfcode: ie:% fl:( br:> va:} ls:[ fo:) rl:( n4:{ ss:| de:> js:| ch:) mo:} zu:) - [Selfcode dekodieren](http://www.peter.in-berlin.de/projekte/selfcode/?code=ie%3A%25+fl%3A%28+br%3A%3E+va%3A%7D+ls%3A%5B+fo%3A%29+rl%3A%28+n4%3A%7B+ss%3A%7C+de%3A%3E+js%3A%7C+ch%3A%29+mo%3A%7D+zu%3A%29) - [Selfcode-Info](http://community.de.selfhtml.org/fanprojekte/selfcode.htm)
    
  3. Hallo Thorsten F.,

    bevor du jetzt mit Ideen überhäuft wirst, solltest du erst mal sagen, was du brauchst:
     - 16 Verschiedene Zufallszahlen
     - Die Zahlen von 1 bis 16 in zufälliger Reihenfolge
     - ???

    Noch eine Bemerkung zu Math.round in Verbindug mit Zufallszahlen:

    var random = Math.random();
    var teiler = 1/16;
    var not_round = random / teiler;
    var round = Math.round(not_round);

    dieses liefert eine Zufallszahl zwischen 0 und 16. Hierbei kommen die 0 und die 16 mit der Wahrscheinlichkeit 1/32, die anderen aber mit 1/16. Wenn du eine Gleichverteilung wünscht, ist floor oder ceil besser.

    Gruß, Jürgen