Permalänk

while loop problem

Hej!

Börjat skolan här nu och vi ska göra ett kortspel med 52 kort.

Jag har skapat Deck så den genererar ut alla valörer från kort 2 upp till ace vilket ace ska generera värdet 14, vilket jag inte lyckats med just ännu.

men jobbar på shuffle nu med.

shuffle(){ let deck = this.deck let curr = deck.length let ind while(curr){ ind = Math.floor(Math.random() * curr--) [deck[curr], deck[ind]] = [deck[ind], deck[curr]] } return deck }

i denna kurs ska vi jobba med utan ; tecken och när jag inte har ett ;

ind = Math.floor(Math.random() * curr--)

efter denna kod så får jag fel meddelande, "cannot create property 'undefined' on number '"exempelvis" 39'.

Vad är det som gör att i min while loop vägrar fungera utan ; i min kod? vad är det för fel jag gör där? Hur man jag fixa så det fungerar på rätt sett utan ; ?

ha det bra!

Visa signatur

Big Bang Theory
Howard Wolowitz

Permalänk
Medlem

Vill du inte ha detta?

while(curr > 0)

Permalänk
Medlem
Skrivet av Howardtheory:

Hej!

Börjat skolan här nu och vi ska göra ett kortspel med 52 kort.

Jag har skapat Deck så den genererar ut alla valörer från kort 2 upp till ace vilket ace ska generera värdet 14, vilket jag inte lyckats med just ännu.

men jobbar på shuffle nu med.

shuffle(){ let deck = this.deck let curr = deck.length let ind while(curr){ ind = Math.floor(Math.random() * curr--) [deck[curr], deck[ind]] = [deck[ind], deck[curr]] } return deck }

i denna kurs ska vi jobba med utan ; tecken och när jag inte har ett ;

ind = Math.floor(Math.random() * curr--)

efter denna kod så får jag fel meddelande, "cannot create property 'undefined' on number '"exempelvis" 39'.

Vad är det som gör att i min while loop vägrar fungera utan ; i min kod? vad är det för fel jag gör där? Hur man jag fixa så det fungerar på rätt sett utan ; ?

ha det bra!

ASI (automatic semicolon insertion) fungerar för det mesta bra — jag använder aldrig semikolon i javascript. Ditt kodstycke tolkas däremot så här:

ind = Math.floor(Math.random() * curr--)[deck[curr], deck[ind]] = [deck[ind], deck[curr]]

Du kan lösa det genom att göra platsbytet i tre steg:

1. spara undan värdet på deck[curr] till en temporärvariabel
2. sätt deck[curr] = deck[ind]
3. sätt deck[ind] = temporärvariabel

Skrivet av Zipparn:

Vill du inte ha detta?

while(curr > 0)

0 är ett "falsy" värde i javascript, så när curr blir 0 kommer while-loopen avslutas.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Avstängd

Fråga från en icke-Java-nisse: varför vill man inte ha semikolon för att avskilja satser?

Permalänk
Medlem

Två saker jag noterar:
1. I första iterationen är curr = 52 vilket får till följd att deck[curr] = 'undefined' då det inte finns ett index 52.
2. Du slutar att loopa när du når index 0 vilket får till följd att det sista kortet i leken inte blandas (dvs deck[0])

formattering
Visa signatur

AMD Ryzen 7 1700X 3.8 GHz 20MB | ASUS PRIME X370-PRO | MSI GeForce GTX 1080 Gaming X 8GB | G.Skill 16GB DDR4 3200 MHz CL14 Flare X | Corsair RM650x 650W

Permalänk
Medlem
Skrivet av videopac:

Fråga från en icke-Java-nisse: varför vill man inte ha semikolon för att avskilja satser?

Det är JavaScript det handlar om (antar jag, TS utelämnade den biten), Java är ett helt annat språk som olyckligtvis har ett liknande namn. Men huruvida man ska använda semikolon eller inte verkar vara en av de mest omtvistade sakerna när det gäller JavaScript, och det beror väl delvis på att det inte finns några särskilt starka argument varken för eller emot.

Oavsett vilken stil man väljer att använda så måste man förstå sig på ASI, eftersom semikolon läggs till av ASI vare sig man vill eller inte. Och på just den punkten kan det kanske vara enklare att inte använda semikolon, eftersom tumregeln då helt enkelt blir att undvika att skriva kod där en rad börjar med (, [, eller ` (se JavaScript Standard Style).

Permalänk
Medlem
Skrivet av videopac:

Fråga från en icke-Java-nisse: varför vill man inte ha semikolon för att avskilja satser?

Aj aj, någon kommer bli förnärmad när du blandar ihop Java med JavaScript vilket är två helt skiljda ting
Utöver personlig preferens vet jag inte varför man skulle välja att inte använda semikolon, särskilt inte om de ändå sätts in automatiskt.
Antagligen kommer man från Python där whitespace är en del av syntaxen och därmed inte behöver semikolon eller måsvingar för att markera avslut eller kodblock.

Visa signatur

AMD Ryzen 7 1700X 3.8 GHz 20MB | ASUS PRIME X370-PRO | MSI GeForce GTX 1080 Gaming X 8GB | G.Skill 16GB DDR4 3200 MHz CL14 Flare X | Corsair RM650x 650W

Permalänk
Medlem
Skrivet av videopac:

Fråga från en icke-Java-nisse: varför vill man inte ha semikolon för att avskilja satser?

Skrivet av noMad17:

Aj aj, någon kommer bli förnärmad när du blandar ihop Java med JavaScript vilket är två helt skiljda ting
Utöver personlig preferens vet jag inte varför man skulle välja att inte använda semikolon, särskilt inte om de ändå sätts in automatiskt.
Antagligen kommer man från Python där whitespace är en del av syntaxen och därmed inte behöver semikolon eller måsvingar för att markera avslut eller kodblock.

Det; är; jätteskönt; att; slippa; sätta; semikolon; mellan; saker; som; ändå; är; tydligt; avgränsade.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Teknocide:

ASI (automatic semicolon insertion) fungerar för det mesta bra — jag använder aldrig semikolon i javascript. Ditt kodstycke tolkas däremot så här:

ind = Math.floor(Math.random() * curr--)[deck[curr], deck[ind]] = [deck[ind], deck[curr]]

Skrivet av Teknocide:

Det; är; jätteskönt; att; slippa; sätta; semikolon; mellan; saker; som; ändå; är; tydligt; avgränsade.

Except when it's not?

Jag skiter för övrigt i vilket, men jag använder semikolon för att jag helt enkelt är van vid det från andra språk.
Jobbar man däremot i ett team så bör man gemensamt komma överens om en standard och hålla fast vid den.

Visa signatur

AMD Ryzen 7 1700X 3.8 GHz 20MB | ASUS PRIME X370-PRO | MSI GeForce GTX 1080 Gaming X 8GB | G.Skill 16GB DDR4 3200 MHz CL14 Flare X | Corsair RM650x 650W

Permalänk
Avstängd
Skrivet av noMad17:

Aj aj, någon kommer bli förnärmad när du blandar ihop Java med JavaScript vilket är två helt skiljda ting
Utöver personlig preferens vet jag inte varför man skulle välja att inte använda semikolon, särskilt inte om de ändå sätts in automatiskt.
Antagligen kommer man från Python där whitespace är en del av syntaxen och därmed inte behöver semikolon eller måsvingar för att markera avslut eller kodblock.

Haha, tja, har inte sysslat med någondera. Men om de sätts in automagiskt så fungerar det ju tydligen inte helt felfritt... den dumma kompilatorn (eller om det är en interpretator, vad vet jag) fattar ju inte hur man tänkt

Skrivet av Teknocide:

Det; är; jätteskönt; att; slippa; sätta; semikolon; mellan; saker; som; ändå; är; tydligt; avgränsade.

Men du använder ju mellanslag, bättre kanske att skriva "Detärjättesköntattslippa..."? Eller är det tänkt så att mellanslag är skiljetecknet men det är även godkänt med mellanslag i en sats? Verkar ju lite snurrigt.

Permalänk
Skrivet av Teknocide:

ASI (automatic semicolon insertion) fungerar för det mesta bra — jag använder aldrig semikolon i javascript. Ditt kodstycke tolkas däremot så här:

ind = Math.floor(Math.random() * curr--)[deck[curr], deck[ind]] = [deck[ind], deck[curr]]

Du kan lösa det genom att göra platsbytet i tre steg:

1. spara undan värdet på deck[curr] till en temporärvariabel
2. sätt deck[curr] = deck[ind]
3. sätt deck[ind] = temporärvariabel

0 är ett "falsy" värde i javascript, så när curr blir 0 kommer while-loopen avslutas.

provade detta nu

shuffle() { let deck = this.deck let current = deck.length let index let temp = deck[current] while(current) { index = Math.floor(Math.random() * current--) temp = deck[index], deck[index] = deck[current] } return deck }

verkar fungera, kan det stämma, ser bra ut nog?

Visa signatur

Big Bang Theory
Howard Wolowitz

Permalänk
Medlem
Skrivet av videopac:

Haha, tja, har inte sysslat med någondera. Men om de sätts in automagiskt så fungerar det ju tydligen inte helt felfritt... den dumma kompilatorn (eller om det är en interpretator, vad vet jag) fattar ju inte hur man tänkt

Men du använder ju mellanslag, bättre kanske att skriva "Detärjättesköntattslippa..."? Eller är det tänkt så att mellanslag är skiljetecknet men det är även godkänt med mellanslag i en sats? Verkar ju lite snurrigt.

Ja;jag;hade;ju;kunnat;skriva;så;här;också;men;mellanslag;känns;mer;lättillgängligt;:)

Fåniga skämt åsido, det är en smaksak antar jag. Jag tycker det ser elegantare ut utan.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Howardtheory:

provade detta nu

shuffle() { let deck = this.deck let current = deck.length let index let temp = deck[current] while(current) { index = Math.floor(Math.random() * current--) temp = deck[index], deck[index] = deck[current] } return deck }

verkar fungera, kan det stämma, ser bra ut nog?

Du sätter aldrig deck[current] till temp

Visa signatur

Kom-pa-TI-bilitet

Permalänk

@Teknocide: Om jag förstår det rätt nu, så tror jag att jag gjort rätt nu

shuffle() { let deck = this.deck let current = deck.length let index let temp = deck[current] while(current) { index = Math.floor(Math.random() * current--) temp = deck[index], deck[index] = deck[current], deck[current] = temp } return deck }

Visa signatur

Big Bang Theory
Howard Wolowitz

Permalänk
Medlem

Om ni på någon nivå kommer jobba som programmerare i grupp med andra har ni säkerligen verktyg som konverterar om koden så att den ser likadan ut som alla andar filer. Då kan ni skriva hur ni vill men när ni sparar filen så sätts det t.ex. semikolon överallt. När syntaxen är avklarad så får man bara hålla tummarna att de andra i ens projekt använder beskrivande namn på sina variabler... och där, där kan vi snacka konflikter.
https://eslint.org/

Permalänk

Hur kan jag lösa detta, får fasen inte till det riktigt, är nybörjare inom javascript med som sagt.

class Deck { constructor() { this.deck = [] const suits = ['Hearts', 'Spades', 'Clubs', 'Diamonds']; const values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King', 'Ace']; for(let s = 0; s < suits.length; s++) { for(let v = 0; v < values.length; v++) { this.deck.push((suits[s] + ' of ' + values[v])) } } } shuffle() { let deck = this.deck let current = deck.length let index let temp while(current) { index = Math.floor(Math.random() * current--) temp = deck[current], deck[current] = deck[index], deck[index] = deck[current], deck[current] = temp } return deck }

så ser helheten ut med uppbyggnaden.

Vi får ej använda ; så vet inte hur jag ska göra i while loopen för att få det att fungera på rätt sätt, känns eller vet att variabeln temp och det som sker där är helknepigt, men vet inte riktigt hur jag ska få till det.

Visa signatur

Big Bang Theory
Howard Wolowitz

Permalänk

tror jag kanske har löst det med

shuffle() { let deck = this.deck let current = deck.length let index let temp while(current) { index = Math.floor(Math.random() * current--) temp = deck[current] deck[current] = deck[index] deck[index] = temp } return deck }

verkar fungera ser det ut som i debuggen och med npm start. Ser ni något fel med detta annars?

Visa signatur

Big Bang Theory
Howard Wolowitz

Permalänk
Medlem

@Howardtheory: Inget direkt fel, men jag hade deklarerat index och temp inne i loopen istället, d.v.s.:

shuffle() { let deck = this.deck let current = deck.length while(current) { let index = Math.floor(Math.random() * current--) let temp = deck[current] deck[current] = deck[index] deck[index] = temp } return deck }

Prestandamässigt spelar det ingen roll eftersom Javascript internt ändå flyttar alla variabler till början av funktionen, men koden blir enklare.

Sen är det som sker med temp egentligen inte alls komplicerat, allt den koden gör är att byta plats på två element. Det kanske blir mer överskådligt med enklare namn, t.ex. om man vill byta värde på x och y:

// Spara värdet på x i en temporär variabel temp = x // Skriv över värdet på x med värdet på y x = y // Skriv över värdet på y med det sparade värdet på x y = temp

Permalänk
Medlem
Skrivet av perost:

Men huruvida man ska använda semikolon eller inte verkar vara en av de mest omtvistade sakerna när det gäller JavaScript, och det beror väl delvis på att det inte finns några särskilt starka argument varken för eller emot.

Du glömde den debatt som oftast dyker upp oavsett språk: tabs vs spaces! För att inte tala om huruvida en indentering ska vara 2 eller 4 spaces... Här snackar vi riktiga problem!

Permalänk
Medlem
Skrivet av perost:

Prestandamässigt spelar det ingen roll eftersom Javascript internt ändå flyttar alla variabler till början av funktionen, men koden blir enklare.

Rätta mig om jag har fel, men när du använder let så stämmer inte ditt påstående då variabeln blir begränsad till sitt scope som i detta fall blir while-loopen. Alltså, om du flyttar in skapandet av variablerna så kan du inte komma åt dessa utanför loopen.

Om du däremot använder var stämmer det att variablerna blir globala i funktionen, d.v.s. även om du faktiskt skapade variabeln inuti while-loopen.

Visa signatur

AMD Ryzen 7 1700X 3.8 GHz 20MB | ASUS PRIME X370-PRO | MSI GeForce GTX 1080 Gaming X 8GB | G.Skill 16GB DDR4 3200 MHz CL14 Flare X | Corsair RM650x 650W

Permalänk
Medlem

@noMad17: Jo, fast jag syftade mer på hur JavaScript optimerar koden, det är därför jag skrev internt. Fast nu blev jag lite osäker på hur det fungerar, det verkar som att let inne i en loop ändå kan vara långsammare än var beroende på vilken JavaScript-motor man använder. Så det kanske inte stämmer när man använder let som du säger.

Permalänk
Datavetare

Även sådana här enkla exempel bör brytas ned i mindre delar, det enligt mottot att ha "funktioner som är så enkla att de är uppenbart korrekt" i stället för "funktioner som inte har några uppenbara fel".

Nu finns risken att det är JS-relaterade fel här, är rudis på JS. Men detta borde göra exakt samma sak som i TS sista inlägg

Algoritmen har i stort tre separata delar:

  • gå igenom alla utom ett element

  • generera ett slumpmässigt index mellan noll och nuvarande index (inklusive)

  • byte plats på element vid aktuellt index och slumpat index

function swap(array, a, b) { const tmp = array[a] array[a] = array[b] array[b] = tmp } function randIndex(limit) { return Math.floor(Math.random() * (limit + 1)) } // Fisher–Yates shuffle function shuffle(array) { for (let i = array.length - 1; i > 0; i--) { swap(array, i, randIndex(i)) } return array }

function swap(array, a, b) { const tmp = array[a] array[a] = array[b] array[b] = tmp } function randIndex(limit) { return Math.floor(Math.random() * (limit + 1)) } // Fisher–Yates shuffle function shuffle(array) { for (let i = array.length - 1; i > 0; i--) { swap(array, i, randIndex(i)) } return array } const suits = ['Hearts', 'Spades', 'Clubs', 'Diamonds']; const values = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King', 'Ace']; // Är inte helt med på att en funktionell lösning är bättre än en iterativ, // är lite write-only code över detta... const deck = suits.reduce((deck, suite) => deck.concat(values.map(value => suite + " of " + value)), []) console.log(shuffle(deck))

Körbart exempel
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
99:e percentilen
Skrivet av Howardtheory:

tror jag kanske har löst det med

index = Math.floor(Math.random() * current--)

verkar fungera ser det ut som i debuggen och med npm start. Ser ni något fel med detta annars?

Jag skulle vilja lyfta en liten sak i raden ovan. Den innehåller en sidoeffekt som inte är så enkel att se om man inte läser noggrant: Uttrycket current-- har som du vet sidoeffekten att dekrementera värdet på current. Sidoeffekter är alltid luriga, och jag tycker att det ofta är bra att försöka göra dem så explicita och synliga som möjligt. Den andra sidoeffekten som raden har, att tilldela ett nytt värde till index, är ju till exempel väldigt tydlig.

Det går inte att kategoriskt döma ut sådan användning av sidoeffekter som jag beskriver ovan, så ingen behöver tolka mitt inlägg som att jag gör det. Det enda jag vill göra är att ge underlag för att kunna göra ett medvetet, välgrundat val. Annars kanske man bara kodar på utan en tanke på vilka lurigheter ens kod innehåller.

Skrivet av noMad17:

Rätta mig om jag har fel, men när du använder let så stämmer inte ditt påstående då variabeln blir begränsad till sitt scope som i detta fall blir while-loopen. Alltså, om du flyttar in skapandet av variablerna så kan du inte komma åt dessa utanför loopen.

Om du däremot använder var stämmer det att variablerna blir globala i funktionen, d.v.s. även om du faktiskt skapade variabeln inuti while-loopen.

Variabler är alltid begränsade till sitt scope. Förstår att du vet hur scoping fungerar i JavaScript men kanske bara använder en felaktig eller otydlig formulering. Det du menar är att en let-variabels scope blir begränsat till det block i vilket variabeln deklareras (medan var-variablers scope är hela funktionen). Är ännu lite mer detaljerat än så, men det är en annan fråga.

Visa signatur

Skrivet med hjälp av Better SweClockers

Permalänk
Medlem
Skrivet av Alling:

Variabler är alltid begränsade till sitt scope. Förstår att du vet hur scoping fungerar i JavaScript men kanske bara använder en felaktig eller otydlig formulering. Det du menar är att en let-variabels scope blir begränsat till det block i vilket variabeln deklareras (medan var-variablers scope är hela funktionen). Är ännu lite mer detaljerat än så, men det är en annan fråga.

Ja, jag uttryckte mig kanske väl klumpigt
Jag menade förstås, som du säger, att let begränsas till blocket där den deklareras (while-loopen i detta fall).

Visa signatur

AMD Ryzen 7 1700X 3.8 GHz 20MB | ASUS PRIME X370-PRO | MSI GeForce GTX 1080 Gaming X 8GB | G.Skill 16GB DDR4 3200 MHz CL14 Flare X | Corsair RM650x 650W