Schneller Tipp Zufälliges Mischen eines Arrays in AS3

Manchmal haben Sie eine Reihe von Elementen - könnten Strings sein, könnten Zahlen sein, Objekte sein, was auch immer - deren Reihenfolge Sie zufällig bestimmen möchten. Dies ist besonders nützlich für Quizspiele und Glücksspiele, ist jedoch für alle möglichen anderen Anwendungen von Nutzen. Die einfachste Methode, die ich dazu gefunden habe, ist, alle Elemente in ein Array zu kleben und dann wie ein Kartenstapel zu mischen. Aber wie können wir das schaffen?? ?

Als einfaches Beispiel verwenden wir die Buchstaben des Alphabets:

 var Buchstaben: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", M, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X" ", Y", "Z"];

Es gibt verschiedene Ansätze, um dieses Array tatsächlich zu sortieren.


Der naive Ansatz

Wir könnten ein zweites Array erstellen und jedes Element des ersten an eine zufällige Position im zweiten kopieren:

Der Code dafür könnte folgendermaßen aussehen (weitere Informationen finden Sie in diesem Quick Tip, um eine zufällige Ganzzahl innerhalb eines bestimmten Bereichs zu erhalten):

 var Buchstaben: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", M, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X" ", Y", "Z"]; var shuffledLetters: Array = neues Array (letters.length); var randomPos: int = 0; für (var i: int = 0; i < letters.length; i++)  randomPos = int(Math.random() * letters.length); shuffledLetters[randomPos] = letters[i]; 

Aber es gibt ein großes Problem. Was ist, wenn die zufällige Position gewählt wurde C ist auch 6?

Hier, EIN wird überschrieben und befindet sich daher nicht im gemischten Array. Das ist nicht das, was wir wollen, also müssen wir prüfen, ob der Slot leer ist, bevor Sie den Brief kopieren, und wählen Sie einen anderen Slot, falls nicht:

 var Buchstaben: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", M, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X" ", Y", "Z"]; var shuffledLetters: Array = neues Array (letters.length); var randomPos: int = 0; für (var i: int = 0; i < letters.length; i++)  randomPos = int(Math.random() * letters.length); while (shuffledLetters[randomPos] != null) //repeat as long as the slot is not empty  randomPos = int(Math.random() * letters.length); //pick a different slot  shuffledLetters[randomPos] = letters[i]; 

Das funktioniert. Das Problem ist, es ist ineffizient. Siehe den Brief EIN wird garantiert in den ausgewählten Slot passen, da es der erste gewählte Buchstabe ist, sodass alle Slots leer sind. Mit B, Es besteht eine Chance von 25 zu 26, dass der erste ausgewählte Platz leer ist. Wenn wir uns auf halbem Weg durch das Alphabet befinden, sinkt diese Chance auf 50/50. Zu der Zeit erreichen wir V, Es besteht eine Chance von 50/50, dass wir bis zum vierte Versuch.

Dies bedeutet, dass wir sehr wahrscheinlich anrufen werden Math.random () Wayyyyy mehr als 26 Mal. Und Math.random () ist eine relativ langsame Funktion. Was können wir noch tun??


Der Middle-Man-Ansatz

Was ist, wenn wir eine Liste aller leeren Schlitze in einem dritte Array, das schrumpfte, als wir durch sie gingen?

? und so weiter, bis der Array leerer Slots keine Elemente enthält. Der Code dafür würde so aussehen:

 var Buchstaben: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", M, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X" ", Y", "Z"]; var shuffledLetters: Array = neues Array (letters.length); var emptySlots: Array = neues Array (); für (var n: int = 0; n < letters.length; n++)  emptySlots.push(n);  var randomPos:Number = 0; var actualSlot:Number = 0; for (var i:int = 0; i < letters.length; i++)  randomPos = int(Math.random() * emptySlots.length); //note emptySlots.length not letters.length actualSlot = emptySlots[randomPos]; shuffledLetters[actualSlot] = letters[i]; emptySlots.splice(randomPos, 1); 

Hier verwenden wir die Array.splice () -Methode, um ein einzelnes Element aus der Liste der leeren Slots zu entfernen. Dadurch wird das Element tatsächlich entfernt und nicht nur der Wert auf festgelegt Null; nach dem Spleißen des ersten Schlitzes, emptySlots.length wird sein 25 eher, als 26.

Diese spleißen() Funktion ist großartig; Wir können es für eine dritte Herangehensweise zum Mischen verwenden, die diese mittlere Manngruppe ausschaltet.


Der Splicing-Ansatz

Anstatt Elemente aus dem Array leerer Slots zu entfernen, wenn wir mit ihnen fertig sind, können wir sie aus dem ursprünglichen, nicht gemischten Array entfernen.

Das hört sich zunächst nicht sehr nützlich an - aber was, wenn wir Elemente aus der Original Array zufällig, anstatt ihre auszuwählen Destinationen zufällig?

? und so weiter, bis das erste Array keine Elemente enthält.

Im Gegensatz zu den beiden anderen Ansätzen enden wir ohne das ursprüngliche Array. Ob dies ein Problem ist oder nicht, hängt von diesem Projekt ab.

Der Code könnte so aussehen:

 var Buchstaben: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", M, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X" ", Y", "Z"]; var shuffledLetters: Array = neues Array (letters.length); var randomPos: Anzahl = 0; für (var i: int = 0; i < shuffledLetters.length; i++) //use shuffledLetters.length because splice() will change letters.length  randomPos = int(Math.random() * letters.length); shuffledLetters[i] = letters[randomPos]; //note this the other way around to the naive approach letters.splice(randomPos, 1); 

In der Tat seit spleißen() gibt ein zurück Array Von allen Elementen, die Sie verbinden, könnten Sie den Code ein wenig vereinfachen:<

 var Buchstaben: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", M, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X" ", Y", "Z"]; var shuffledLetters: Array = neues Array (letters.length); var randomPos: Anzahl = 0; für (var i: int = 0; i < shuffledLetters.length; i++)  randomPos = int(Math.random() * letters.length); shuffledLetters[i] = letters.splice(randomPos, 1)[0]; //since splice() returns an Array, we have to specify that we want the first (only) element 

Das ist ordentlich. Ich habe noch einen Ansatz zu teilen; dieses unterscheidet sich sehr von den anderen, die wir bisher verwendet haben.


Der Sortieransatz

Arrays haben eine Methode sort (), die standardmäßig alle Elemente des Arrays in aufsteigender alphanumerischer Reihenfolge anordnet, wie folgt:

 var mixedLetters: Array = ["G", "B", "P", "M", "F"]; mixedLetters.sort (); // mixedLetters ist jetzt ["B", "F", "G", "M", "P"]

Sie können Optionen an diese Methode übergeben, z Array.DESCENDING, was die Sortierung umkehrt:

 var mixedLetters: Array = ["G", "B", "P", "M", "F"]; mixedLetters.sort (Array.DESCENDING); // mixedLetters ist jetzt ["P", "M", "G", "F", "B"]

(Es gibt andere Optionen, und Sie können beliebig viele davon übergeben.)

Sie können auch einen Verweis auf a übergeben Funktion, In diesem Abschnitt wird festgelegt, in welcher Reihenfolge sich zwei Elemente befinden. Diese Funktion kann beispielsweise zur numerischen Sortierung verwendet werden:

 Funktion numericalSort (a: Number, b: Number): Number if (a < b) return -1; if (a == b) return 0; if (a > b) 1 zurückgeben; 

Flash betrachtet jedes Paar benachbarter Elemente im Array und ordnet sie entsprechend dieser Funktion neu an: Sie tauscht sie aus, wenn der Wert vorhanden ist 1 wird zurückgegeben und lässt sie ansonsten alleine. (Es sei denn du passierst Array.DESCENDING sowie die Funktion, in diesem Fall tauscht sie den Wert aus -1 wird zurückgegeben und lässt sie ansonsten alleine.) Flash wiederholt dies immer wieder im gesamten Array, bis alle Paare zurückkehren 0 oder -1 (0 oder 1 wenn verwenden Array.DESCENDING).

Wir können uns damit anstellen. Anstatt ihm einen echten Grund zu geben, warum zwei Elemente ausgetauscht werden sollten, können wir einfach sagen, dass sie nach dem Zufallsprinzip ausgetauscht werden sollen, indem eine Sortierfunktion wie folgt verwendet wird:

 function randomSort (a: *, b: *): Number // * bedeutet jede Art von Eingabe if (Math.random () < 0.5) return -1; else return 1; 

Einfach! Jetzt können wir es wie folgt in unserem Code verwenden:

 Funktion randomSort (a: *, b: *): Anzahl if (Math.random () < 0.5) return -1; else return 1;  var letters:Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]; letters.sort(randomSort); //(no need for the shuffledLetters[] Array)

Bitte beachten Sie, dass das resultierende Array nicht so zufällig gemischt wird wie die anderen Ansätze, die wir verwendet haben. Bei diesem Ansatz gibt es keine Chance von nur 1/26 irgendein gegebener Brief landet in irgendein gegebenen Schlitz. Dies liegt daran, dass wir nur benachbarte Elementpaare austauschen und nicht mehr tun. Trotzdem ist es eine nette Methode :)

Es gibt viele andere Methoden, ich weiß. Haben Sie etwas besser als diese?

Bearbeiten: Hier ist ein großartiger Beitrag mit einigen coolen Visualisierungen, die den Fisher-Yates-Shuffle erklären, der an Ort und Stelle funktioniert. Ich empfehle es sehr!