Generate unique number within range (0 - X), keeping a history to prevent duplicates
I wrote this function. It keeps its own array with a history of generated numbers, preventing initial duplicates, continuing to output a random number if all numbers in the range have been outputted once:
// Generates a unique number from a range
// keeps track of generated numbers in a history array
// if all numbers in the range have been returned once, keep outputting random numbers within the range
var UniqueRandom = { NumHistory: new Array(), generate: function(maxNum) {
var current = Math.round(Math.random()*(maxNum-1));
if (maxNum > 1 && this.NumHistory.length > 0) {
if (this.NumHistory.length != maxNum) {
while($.inArray(current, this.NumHistory) != -1) { current = Math.round(Math.random()*(maxNum-1)); }
this.NumHistory.push(current);
return current;
} else {
//unique numbers done, continue outputting random numbers, or we could reset the history array (NumHistory = [];)
return current;
}
} else {
//first time only
this.NumHistory.push(current);
return current;
}
}
};
Here's a working Fiddle
I hope this is of use to someone!
Edit: as pointed out by Pointy below, it might get slow with a large range (here is a
fiddle, going over a range from 0-1000, which seems to run fine). However; I didn't require a very large range, so perhaps this function is indeed not suited if you look to generate and keep track of an enormous range.
Generate random number within range without repeating numbers in javascript
for (var i = 0, ar = []; i < 80; i++) {
ar[i] = i;
}
// randomize the array
ar.sort(function () {
return Math.random() - 0.5;
});
// You have array ar with numbers 0 to 79 randomized. Verifyconsole.log(ar);
// take out elements like thisar.pop()
run for random numbers and keep state
One approach would be to create an array to store existing selections, push selected elements to an array, check if the array contains the element and if the array storing values .length
is greater than or equal to maximum range minus minimum range.
It is not clear from description at Question what should occur once all of the elements in the range have been returned?
var range = [10, 20];var not = [];
function randomRange(range, n) { if (not.length >= range[1] - range[0]) { return "all numbers in range used" } var curr = []; var res = []; for (let i = range[0]; i < range[1]; i++) { if (!not.some(function(num) { return i == num }) && not.length < range[1] - range[0]) { curr.push(i) } } for (let i = 0; i < n; i++) { var j = curr.splice(Math.floor(Math.random() * curr.length), 1)[0]; res[i] = not[not.length] = j; }
return res.filter(Boolean)}
console.log(randomRange(range, 3));console.log(randomRange(range, 3));console.log(randomRange(range, 3));console.log(randomRange(range, 3));console.log(randomRange(range, 3));
Javascript : Making an random array
function randomArray(n) {
var array = [];
for (i = 0; i < n; i++) {
array[i] = i;
}
var newArray = [];
for (i = 0; i < n; i++) {
var num = Math.round(Math.random() * (n - i - 1));
newArray[i] = array[num];
array.splice(num, 1);
}
alert(newArray);
}
randomArray(100);
How to generate an array with not repeating numbers in ES6?
You could take a Set
and fill this set until the wanted size.
var numbers = new Set;
while (numbers.size < 6) numbers.add(Math.floor(Math.random() * 53));
console.log(...numbers);
random numbers from a small range without multiple repeats
What you are after isn't a pure uniform distribution, as @Henry said.
To enforce your constraint, I think that the best solution is to include a decay factor into your random number generator. As the sequence of numbers increases, the probability of that number appearing next decreases.
I implemented some prototype code in python 3, since my cpp skills are a bit rusty at the moment, but the basic concept is easily translatable to cpp. Here it is:
def my_random(range: int, iterations: int, decay_rate :float = 2) -> List[int]:
assert range > 0, "`range` must be a positive non-zero integer"
if range == 1:
return [0] * iterations
last_num: int = 0
last_prob: float = 1/range
rand_num_lst: List[int] = []
while iterations > 0:
rnd = random() # generates a random number: 0 <= rnd < 1
if rnd < last_prob:
num = last_num
last_prob /= decay_rate
else:
# The `int` function is converting the float into integer by
# flooring the number
num = int( (rnd - last_prob) / (1 - last_prob) * (range - 1) )
if num >= last_num:
num += 1
last_num = num
last_prob = 1/range/decay_rate
rand_num_lst.append(num)
iterations -= 1
return rand_num_lst
Note that in Python3 the default division is float division, meaning that 1/2 = 0.5
instead of 1/2 = 0
as it happened in Python2.
I ran some tests to check the maximum sequence length and if the distribution of numbers generated by this is still uniformly distributed, and it seems to continue to hold those properties:
Running with range = 2
and different decay rates:
decay_rate: 2.00000 max sequence length: 6 number count: {0: 499830, 1: 500170}
decay_rate: 1.50000 max sequence length: 6 number count: {0: 499455, 1: 500545}
decay_rate: 1.25000 max sequence length: 9 number count: {0: 500241, 1: 499759}
decay_rate: 1.12500 max sequence length: 11 number count: {0: 499799, 1: 500201}
decay_rate: 1.06250 max sequence length: 14 number count: {0: 500655, 1: 499345}
decay_rate: 1.03125 max sequence length: 16 number count: {0: 500495, 1: 499505}
decay_rate: 1.01562 max sequence length: 16 number count: {0: 500010, 1: 499990}
decay_rate: 1.00781 max sequence length: 18 number count: {0: 499748, 1: 500252}
decay_rate: 1.00391 max sequence length: 18 number count: {0: 499987, 1: 500013}
decay_rate: 1.00195 max sequence length: 21 number count: {0: 499503, 1: 500497}
decay_rate: 1.00098 max sequence length: 21 number count: {0: 500495, 1: 499505}
decay_rate: 1.00000 max sequence length: 19 number count: {0: 499451, 1: 500549}
Running with range = 5
and different decay rates:
decay_rate: 2.00000 max sequence length: 5 number count: {0: 200314, 1: 199245, 2: 200213, 3: 199962, 4: 200266}
decay_rate: 1.50000 max sequence length: 5 number count: {0: 199372, 1: 199829, 2: 199937, 3: 200527, 4: 200335}
decay_rate: 1.25000 max sequence length: 6 number count: {0: 199373, 1: 199784, 2: 200561, 3: 200062, 4: 200220}
decay_rate: 1.12500 max sequence length: 8 number count: {0: 199752, 1: 199931, 2: 200579, 3: 200287, 4: 199451}
decay_rate: 1.06250 max sequence length: 8 number count: {0: 199280, 1: 200286, 2: 199688, 3: 200446, 4: 200300}
decay_rate: 1.03125 max sequence length: 8 number count: {0: 199577, 1: 199582, 2: 200652, 3: 199870, 4: 200319}
decay_rate: 1.01562 max sequence length: 9 number count: {0: 200442, 1: 199916, 2: 200142, 3: 199729, 4: 199771}
decay_rate: 1.00781 max sequence length: 9 number count: {0: 199784, 1: 200544, 2: 199921, 3: 199557, 4: 200194}
decay_rate: 1.00391 max sequence length: 9 number count: {0: 199920, 1: 199054, 2: 200303, 3: 200833, 4: 199890}
decay_rate: 1.00195 max sequence length: 9 number count: {0: 200011, 1: 200530, 2: 199806, 3: 200321, 4: 199332}
decay_rate: 1.00098 max sequence length: 10 number count: {0: 199741, 1: 199861, 2: 199822, 3: 200081, 4: 200495}
decay_rate: 1.00000 max sequence length: 9 number count: {0: 199717, 1: 199184, 2: 200182, 3: 200891, 4: 200026}
Of course you can explicitely code something like: if the running sequence has a length greater than X
, just ignore the number and generate one different than the last random number. Although I'm not sure if this method would continue to be uniformly distributed.
Related Topics
In JavaScript, How to Check If an Array Has Duplicate Values
Access Denied to Jquery Script on Ie
Maximum Call Stack Size Exceeded on Npm Install
How to Close a Dropdown on Click Outside
Understanding Ajax Cors and Security Considerations
How to Add Predefined Length to Audio Recorded from Mediarecorder in Chrome
How to Load a JavaScript File Dynamically
Where to Save a Jwt in a Browser-Based Application and How to Use It
How to Convert String to Number According to Locale (Opposite of .Tolocalestring)
Jasmine: Async Callback Was Not Invoked Within Timeout Specified by Jasmine.Default_Timeout_Interval
About Closure, Lexicalenvironment and Gc
Jquery Equivalent of JavaScript's Addeventlistener Method
How to Do a Deep Comparison Between 2 Objects with Lodash
Dynamically Update Values of a Chartjs Chart
Garbage Collection with Node.Js