Reputation: 5745
I would like get a random number in a range excluding one number (e.g. from 1 to 1000 exclude 577). I searched for a solution, but never solved my issue.
I want something like:
Math.floor((Math.random() * 1000) + 1).exclude(577);
I would like to avoid for
loops creating an array as much as possible, because the length is always different (sometimes 1 to 10000, sometimes 685 to 888555444, etc), and the process of generating it could take too much time.
I already tried:
Javascript - Generating Random numbers in a Range, excluding certain numbers
How can I generate a random number within a range but exclude some?
How could I achieve this?
Upvotes: 19
Views: 18984
Reputation: 1
import random
def rng_generator():
a = random.randint(0, 100)
if a == 577:
rng_generator()
else:
print(a)
#main()
rng_generator()
Upvotes: 0
Reputation: 69522
The fastest way to obtain a random integer number in a certain range [a, b]
, excluding one value c
, is to generate it between a
and b-1
, and then increment it by one if it's higher than or equal to c
.
Here's a working function:
function randomExcluded(min, max, excluded) {
var n = Math.floor(Math.random() * (max-min) + min);
if (n >= excluded) n++;
return n;
}
This solution only has a complexity of O(1).
Upvotes: 32
Reputation: 1
Exclude the number from calculations:
function toggleRand() {
// demonstration code only.
// this algorithm does NOT produce random numbers.
// return `0` - `576` , `578` - `n`
return [Math.floor((Math.random() * 576) + 1)
,Math.floor(Math.random() * (100000 - 578) + 1)
]
// select "random" index
[Math.random() > .5 ? 0 : 1];
}
console.log(toggleRand());
Alternatively, use String.prototype.replace()
with RegExp
/^(577)$/
to match number that should be excluded from result; replace with another random number in range [0-99]
utilizing new Date().getTime()
, isNaN()
and String.prototype.slice()
console.log(
+String(Math.floor(Math.random()*(578 - 575) + 575))
.replace(/^(577)$/,String(isNaN("$1")&&new Date().getTime()).slice(-2))
);
Could also use String.prototype.match()
to filter results:
console.log(
+String(Math.floor(Math.random()*10))
.replace(/^(5)$/,String(isNaN("$1")&&new Date().getTime()).match(/[^5]/g).slice(-1)[0])
);
Upvotes: -2
Reputation: 69522
You could just continue generating the number until you find it suits your needs:
function randomExcluded(start, end, excluded) {
var n = excluded
while (n == excluded)
n = Math.floor((Math.random() * (end-start+1) + start));
return n;
}
myRandom = randomExcluded(1, 10000, 577);
By the way this is not the best solution at all, look at my other answer for a better one!
Upvotes: 2
Reputation: 175
One possibility is not to add 1, and if that number comes out, you assign the last possible value.
For example:
var result = Math.floor((Math.random() * 100000));
if(result==577) result = 100000;
In this way, you will not need to re-launch the random method, but is repeated. And meets the objective of being a random.
Upvotes: 5
Reputation: 7328
As @ebyrob suggested, you can create a function that makes a mapping from a smaller set to the larger set with excluded values by adding 1 for each value that it is larger than or equal to:
// min - integer
// max - integer
// exclusions - array of integers
// - must contain unique integers between min & max
function RandomNumber(min, max, exclusions) {
// As @Fabian pointed out, sorting is necessary
// We use concat to avoid mutating the original array
// See: http://stackoverflow.com/questions/9592740/how-can-you-sort-an-array-without-mutating-the-original-array
var exclusionsSorted = exclusions.concat().sort(function(a, b) {
return a - b
});
var logicalMax = max - exclusionsSorted.length;
var randomNumber = Math.floor(Math.random() * (logicalMax - min + 1)) + min;
for(var i = 0; i < exclusionsSorted.length; i++) {
if (randomNumber >= exclusionsSorted[i]) {
randomNumber++;
}
}
return randomNumber;
}
Also, I think @JesusCuesta's answer provides a simpler mapping and is better.
Update: My original answer had many issues with it.
Upvotes: 3
Reputation: 674
To expand on @Jesus Cuesta's answer:
function RandomNumber(min, max, exclusions) {
var hash = new Object();
for(var i = 0; i < exclusions.length; ++i ) { // TODO: run only once as setup
hash[exclusions[i]] = i + max - exclusions.length;
}
var randomNumber = Math.floor((Math.random() * (max - min - exclusions.length)) + min);
if (hash.hasOwnProperty(randomNumber)) {
randomNumber = hash[randomNumber];
}
return randomNumber;
}
Note: This only works if max - exclusions.length > maximum exclusion. So close.
Upvotes: 1
Reputation: 305
Generate a random number and if it matches the excluded number then add another random number(-20 to 20)
var max = 99999, min = 1, exclude = 577;
var num = Math.floor(Math.random() * (max - min)) + min ;
while(num == exclude || num > max || num < min ) {
var rand = Math.random() > .5 ? -20 : 20 ;
num += Math.floor((Math.random() * (rand));
}
Upvotes: 0