A random number between 1 and 4 that's not ano

2019-02-20 23:39发布

问题:

For some reason the following code doesn't work.

var a1 = Math.floor(Math.random()*4+1); 

//Answer2
for(a2 = 0; a2 != a1 && a2 != 0; a2 = Math.floor(Math.random()*4+1)){
    alert(a2);
}

I'm trying to get "a2" to be a int from 1-4 but not equivalent to "a1".

What's wrong? Thanks in advance!!!

EDIT:

Thank you all for your help! Here's my final result:

var a1, a2;
a1 = Math.floor(Math.random()*4+1); 
a2 = a1;

while(a2 == a1){
        a2 = Math.floor(Math.random() * 3 + 1);
        alert(a2);
}

回答1:

How about a while loop instead? Initialise a2 = a1 and then:

while(a2 == a1) {
    a2 = Math.floor(Math.random() * 4 + 1);
}


回答2:

The logic of your test is inverted. For loops continue to execute while the test is true, not if it fails. Rather than: a2 != a1 && a2 != 0 you should have (a2 == a1) || (a2 == 0). Though also keep in mind that the alert will also only be executed in that case when a2 is an invalid state, though an alert following the for should be valid.

Or if you're looking for the fun math-y way to do it using modular arithmetic (no retries necessary):

a2 = (Math.floor(Math.random() * 3 + (a1 + 1)) % 4) || 4


回答3:

Try with this function. It'll give you an array with numbers from 1 to max in random order. Then you can use it to assign a value to a variable and it'll never repeat:

Edit: I found a purely functional way to do it:

function randomRange(min, max) {
  return (new Array(++max-min))
    .join('.').split('.')
    .map(function(v,i){ return min+i })
    .sort(function(){ return 0|Math.random()*max });
}

console.log(rand(1,4)); //-> [4,2,1,3] random array from 1 to 4

var arr = rand(1,4);
var a = arr[0];
var b = arr[1];
...

Edit 2: Seems like the above has problems with some browsers, check out Random but just in Chrome for a better solution.

Demo: http://jsbin.com/ohohum/1/edit (run multiple times to see the randomness)



回答4:

Just add one if the number is greater than or equal to the one you want to exclude:

var a2 = Math.floor(Math.random() * 3 + 1);

if(a2 >= a1) {
    a2++;
}


回答5:

You are choosing a new a2 value when a2 is not the same as a1 or zero. This is backwards - you set a2 to zero before the loop, so it never executes.

You need to loop while a2 is either zero, or equal to a1:

var a1 = Math.floor(Math.random()*4+1); 

//Answer2
for(a2 = 0; a2 == a1 || a2 == 0; a2 = Math.floor(Math.random()*4+1)){
    // nothing here
}   
alert(a2);


回答6:

There are two standard ways of doing this kind of thing. I'm considering a slightly more general framework though

Sample from a filtered list

  1. Create the array of base values to select from

    var values = [1,2,3,4]
    
  2. Remove the values you're not interested in

    values = Array.filter( values, function(x) { return x!=a1; } )
    
  3. Select a value at random from the list

    var a2 = values[Math.floor(Math.random()*values.length)];
    

Use rejection sampling

  1. Create the array of values to select

     var values = [1,2,3,4]
    
  2. Select a value at random and retry until it succeeds

     var a2 =  values[Math.floor(Math.random()*values.length)];
     while( a2==a1 )
     {
       a2 = values[Math.floor(Math.random()*values.length)];
     }
    

Comparison

If we consider n to be the length of the initial list and m to be the number of elements removed, then the filtered version does n comparisons to build the filtered list of length n-m, but only one random number generation. In comparison the rejection method does on average n/(n-m) comparisons and random number generations.