1

I'm confused as to why the below produces the same pairs of values for race and gender in each iteration through the for loop. I would imagine the initial seed value for random() (not explicitly declared in my code) is taken in the first iteration and then the loop proceeds to the next value in the random sequence based on the initial seed, but it appears that is not the case. Instead, it appears to use the same seed/value for each iteration, leading to identical values of race and gender across each iteration.

Minimal working example:

    // Two arrays
    var race = ["B","W"];
    var gender = ["F", "M"];	
    
    for (i = 0; i < 6; i++) {
            var race = race[Math.floor(Math.random()*race.length)];
            var gender =  gender[Math.floor(Math.random()*gender.length)];
            document.write(race)
            document.write(gender)
            } 

    // Example result: BMBMBMBMBMBM (BM repeated 6 times)

Is there someway of looping through using independently drawn values instead of producing identical values for each loop iteration? Apparently this has been answered in C++ and there are many questions on Javascript seeding, but not this.

1
  • 2
    In the code snippet you are using "race" and "gender" for both the array and the randomly generated variables. You need to use 4 different names. Commented May 14, 2020 at 15:02

3 Answers 3

2

In the code snippet you are using "race" and "gender" for both the array and the randomly generated variables. You need to use 4 different names.

    // Two arrays
    var races = ["B","W"];
    var genders = ["F", "M"];	
    
    for (i = 0; i < 6; i++) {
            var race = races[Math.floor(Math.random()*races.length)];
            var gender =  genders[Math.floor(Math.random()*genders.length)];
            document.write(race)
            document.write(gender)
            } 

    // Example result: BMBMBMBMBMBM (BM repeated 6 times)

If you had used "const" and "let" you would have received an error message.

    // Two arrays
    const race = ["B","W"];
    const gender = ["F", "M"];	
    
    for (i = 0; i < 6; i++) {
            let race = race[Math.floor(Math.random()*race.length)];
            let gender =  gender[Math.floor(Math.random()*gender.length)];
            document.write(race)
            document.write(gender)
            } 

Sign up to request clarification or add additional context in comments.

7 Comments

Might also mention why problems like this would not be possible when using let or const
Note that I am accepting this as an answer for most directly answering the question but that the answer by @user120242 is more helpful for the technical explanation of hoisting.
@user3614648 that was actually my intention, which is why I left out the actual answer, that already existed in the other answers
@user3614648 look at my runnable snippet example for explanation of that and look at the output of console.log. I also put comments in the code to explain it. The second iteration is acting on the string "M"[(length=1 so it's always 0)]
@user3614648 ah I see your confusion. the output of console.log makes it look like it's one value. I've changed it so you can take a look again to see what's happening. also remember the first iteration is two arrays being coerced into strings
|
1

Take a look at your variable names - you reuse race and gender as the arrays and then assign a value to them. Did a quick mockup:

const race = ["B","W"];
const gender = ["F", "M"];    

for (i = 0; i < 6; i++) {
  let rand1 = Math.random();
  let rand2 = Math.random();
  console.log(`Random 1: ${rand1}, Random 2: ${rand2}`);
  let r = race[Math.floor(rand1*race.length)];
  let g =  gender[Math.floor(rand2*gender.length)];
  console.log(`Race: ${r}, Gender: ${g}`);
}

1 Comment

Thank you! I guess brain wasn't on. It's weird that this produces console.log(race) within the loop where the first and last elements are not ["B","W"] though?
1

Javascript will move var declarations to the top of the scope context due to hoisting.
https://www.w3schools.com/js/js_hoisting.asp
For a more accurate description you can read this, but the above description is more conceptually accessible: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

Your code actually ends up equivalent to this:

// Two arrays
var race = ["B","W"];
var gender = ["F", "M"];    

for (i = 0; i < 6; i++) {
        race = race[Math.floor(Math.random()*race.length)];
        gender =  gender[Math.floor(Math.random()*gender.length)];
        document.write(race)
        document.write(gender)
        } 

// Example result: BMBMBMBMBMBM (BM repeated 6 times)

I've inserted a console.log in the code below, to show what is happening:

// Two arrays
    var race = ["B","W"];
    var gender = ["F", "M"];	
    
    for (i = 0; i < 6; i++) {
// note that after the first loop, you are actually just using the string
// the race[] is actually just taking 1 character from race, or ie ("M F")[0]
console.log("race=",race,"gender=",gender);
            var race = race[Math.floor(Math.random()*race.length)];
            var gender =  gender[Math.floor(Math.random()*gender.length)];
            document.write(race)
            document.write(gender)
            } 

    // Example result: BMBMBMBMBMBM (BM repeated 6 times)

It is generally recommended as best practice that you use let and const instead of var to avoid introducing bugs like these, since let and const are not hoisted and discourage reusing the variables in ways that may cause unexpected behavior like this.

2 Comments

This makes it clearer. So just use something like race2 or gender2 and the output of gender2 and race2 will be what I want.
Yes, so using a separate variable would give you what you want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.