Hurtig Tips Slik slår du tilfeldig et array i AS3

Noen ganger har du et sett med elementer - kan være Strings, kunne være tall, kunne være objekter, uansett - hvis rekkefølge du vil randomisere. Dette er spesielt nyttig for spørrekonkurranser og sjansespill, men kommer til nytte i alle andre applikasjoner. Den enkleste metoden jeg har funnet for å gjøre dette er å holde alle elementene i et Array og deretter blande det som en kortstokk. Men hvordan kan vi det? ?

Som et enkelt eksempel bruker vi bokstavene i alfabetet:

 var bokstaver: 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 "];

Det er forskjellige tilnærminger vi kan ta for å faktisk sortere denne gruppen.


Den naive tilnærmingen

Vi kunne lage en andre array, og kopiere hvert element av det første til en tilfeldig posisjon i det andre:

Koden for det kan se slik ut (se denne raske tipsen om å få et tilfeldig heltall innen et bestemt område for flere detaljer):

 var bokstaver: 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 = new Array (letters.length); var randomPos: int = 0; for (var jeg: int = 0; i < letters.length; i++)  randomPos = int(Math.random() * letters.length); shuffledLetters[randomPos] = letters[i]; 

Men det er et stort problem. Hva om tilfeldig posisjon plukket for C er også 6?

Her, EN blir overskrevet, og vil derfor ikke være i blandet rekkefølge. Det er ikke det vi ønsker, så vi må sjekke at sporet er tomt før du kopierer brevet over, og velg et annet spor hvis det ikke er det:

 var bokstaver: 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 = new Array (letters.length); var randomPos: int = 0; for (var jeg: 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]; 

Det fungerer. Problemet er at det er ineffektivt. Se brevet EN er garantert å passe inn i sporet plukket, fordi det er det første bokstaver valgt, så alle sporene vil være tomme. Med B, Det er en 25 i 26 sjanse for at den første sporet plukket vil være tom. Når vi er halvveis gjennom alfabetet, faller denne sjansen til 50/50. Når vi når V, Det er en 50/50 sjanse for at vi ikke finner et tomt spor til fjerde forsøk.

Dette betyr at vi sannsynligvis vil ringe Math.random () Wayyyyy mer enn 26 ganger. Og Math.random () er en relativt langsom funksjon. Hva er en annen tilnærming vi kan ta?


Middle-Man Approach

Hva om vi lagret en liste over alle de tomme sporene i a tredje array, som ville krympe når vi gikk gjennom dem?

? og så videre, gjentas til mengden tomme spor ikke inneholder noen elementer. Koden for det ville se slik ut:

 var bokstaver: 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 = new Array (letters.length); var emptySlots: Array = new Array (); for (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); 

Her bruker vi metoden Array.splice () for å fjerne et enkelt element fra listen over tomme spor. Dette fjerner faktisk elementet, i stedet for bare å sette verdien til null; Så, etter å ha splekket den første sporet, emptySlots.length vil være 25 heller enn 26.

Dette spleise () funksjonen er stor; Vi kan bruke den til en tredje tilnærming til å blande det som skjærer ut denne mellommannen.


The Splicing Approach

I stedet for å fjerne elementer fra en rekke tomme spor når vi er ferdige med dem, kan vi fjerne dem fra den opprinnelige, unshuffled arrayen.

Dette høres ikke veldig nyttig først - men hva om vi plukket elementer fra opprinnelig array tilfeldig, i stedet for å plukke sine velsen tilfeldig?

? og så videre, til den første gruppen inneholder ingen elementer.

I motsetning til de to andre tilnærmingene, ender vi opp uten den opprinnelige gruppen. Om dette er et problem eller ikke, avhenger av dette prosjektet.

Koden kan se slik ut:

 var bokstaver: 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 = new Array (letters.length); var randomPos: Number = 0; for (var jeg: 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); 

Faktisk siden spleise () returnerer en Array av alle elementene du spleiser, kan vi forenkle koden litt:<

 var bokstaver: 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 = new Array (letters.length); var randomPos: Number = 0; for (var jeg: 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 

Det er neater. Jeg har en tilnærming til å dele; dette er veldig forskjellig fra de andre vi har brukt hittil.


Sorteringsmetoden

Arrays har en metode, sort (), som som standard omarrangerer alle elementene i arrayet i stigende alfanumerisk rekkefølge, slik som:

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

Du kan overføre alternativer til denne metoden, som Array.DESCENDING, som reverserer rekkefølgen av sorten:

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

(Det finnes andre alternativer, og du kan passere så mange av dem som du vil.)

Du kan også sende en referanse til a funksjon, som forteller Flash hvordan du bestemmer hvilken rekkefølge noen to elementer tilhører. For eksempel kan denne funksjonen brukes til numerisk sortering:

 funksjon numericalSort (a: Nummer, b: Nummer): Nummer hvis (a < b) return -1; if (a == b) return 0; if (a > b) returnere 1; 

Flash ser på hvert par tilgrensende elementer i arrayet, og omarrangerer dem i henhold til denne funksjonen: det bytter dem om verdien 1 returneres, og etterlater dem alene ellers. (Med mindre du passerer Array.DESCENDING så vel som funksjonen, i så fall bytter den dem om verdien -1 returneres, og etterlater dem alene ellers.) Flash gjentar dette over hele gruppen om og om igjen til alle parene kommer tilbake 0 eller -1 (0 eller 1 hvis du bruker Array.DESCENDING).

Vi kan rote med dette. I stedet for å gi det en ekte grunn til at noen to elementer skal byttes, kan vi bare fortelle det å bytte dem tilfeldig, ved hjelp av en slags funksjon som denne:

 funksjonen randomSort (a: *, b: *): Nummer // * betyr noen form for inngang if (Math.random () < 0.5) return -1; else return 1; 

Lett! Nå kan vi bruke den i vår kode som så:

 funksjonen randomSort (a: *, b: *): Nummer 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)

Vær oppmerksom på at den resulterende arrayen ikke vil bli like tilfeldig blandet som de andre tilnærmingene vi har brukt - i denne tilnærmingen er det ikke en jevn 1/2 sjanse for at noen gitt brev vil ende opp i noen gitt spor. Dette skyldes at vi bare bytter tilgrensende par elementer, og gjør ikke mer enn det. Likevel er det en fin måte :)

Det er mange andre metoder, jeg vet. Fikk noen du liker bedre enn disse?

Redigere: Her er et flott innlegg med noen veldig kule visualiseringer, og forklarer Fisher-Yates shuffle, som fungerer på plass. Jeg anbefaler det!