Related
The solution that i've been working on so far:
function solution(elements) {
let numOfShifts;
let shift = shiftedArray(elements);
for(i = 0; i < shift.length; i++){
//Here is where i'm getting stuck... how do i continue through the loop even after the first false is returned
//until all arrays are checked for equality?
if(areEqual(shift[i])){
numOfShifts = i
}else return -1;
}
return numOfShifts;
};
function shiftedArray(array){
let shiftedArrays = [];
for(let i = array.length -1 ; i >= 1; i--){
// first element is simply a formula to create chunk 1
let firstElement = array.length - (i % array.length);
//the result of first element.
let chunk1 = array.slice(firstElement);
//the remaining numbers
let chunk2 = array.slice(0, firstElement);
//Copy of both chunks now merged and pushed into shifted arrays
shiftedArrays.push([...chunk1, ...chunk2]);
};
return shiftedArrays;
}
function areEqual(shift){
let sortedShift = [...shift].sort((a ,b) => {
return a - b
});
//takes in a single shift and does a deep check to see if the array is equal to sorted version
if(sortedShift.length === shift.length){
return sortedShift.every((element, index) => {
if(element === shift[index]){
return true;
}
return false;
})
}
}
console.log(solution([1,4,2,3]));
console.log(solution([[2, 3, 4, 5, 6, 7, 8, 9, 10, 1]]))
How do I keep the for loop running even after the first false is returned from the areEqual() function?
A side note: I understand that this could probably use some refactoring... like, I was working on this with someone earlier and they mentioned how I can simply shift the array by writing a helper function like shiftArray(arr){return arr.push(arr.pop())} but I don't get how that implementation would work considering that all that's returned is the value that was taken out of the array, not the new shifted array.
You may be doing too much work.
Say you have an array A of n integers, zero indexed.
Parse the array from index 0 to n mod n (so 0 twice). Count the number of pairs where the latter integer is less than the former, and store the first index where this happens.
If the count is 1 and the location is k (so A[k] < A[k-1]), then a cyclic shift of either -k or n-k will convert A to a sorted array. If the count is greater than 1 then there's no solution.
E.g., [4,5,0,1,2,3] -- we see k=2 is the only index which has a value below its predecessor, and a cyclic shift of -2 or 4 forms [0,1,2,3,4,5] which is sorted.
This question already has answers here:
How do I extract even elements of an Array?
(8 answers)
How to do a script for odd and even numbers from 1 to 1000 in Javascript?
(8 answers)
Closed 2 years ago.
I've spent an embarrassing amount of time on this question only to realize my function is only right 50% of the time. So the goal here is to return only the odd numbers of all the numbers in between the two arguments. (for instance if the arguments are 1 and 5 i'd need to return 2 & 3) the function I wrote is completely dependent on the first argument. if it's even my function will return odds, but if the first number is odd it'll return evens. does anyone know how i can fix this?
function oddNumbers(l, r) {
const arr = [];
const theEvens = [];
for (let i= l; i<r; i++) {
arr.push(i)
}
console.log(arr)
for (let i= 0; i < arr.length; i+= 2 ) {
const evens = arr[0] + i;
theEvens.push(evens);
}
theEvens.forEach(item => arr.splice(arr.indexOf(item), 1));
console.log(arr)
}
oddNumbers(2, 20);
I modified the code a bit to return only odd numbers
We use the % operator that behaves like the remainder operator in math:
so when we say i % 2 if the number is even the result of the operation will be 0
but when the "i" is an odd number the result will be 1
so now we can filter the even from the odd numbers using this operation
function oddNumbers(l, r) {
const arr = [];
for (let i= l; i<r; i++) {
if(i % 2 !== 0) arr.push(i);
}
console.log(arr);
}
oddNumbers(2, 20);
You can loop from initial to end parameters and get odd numbers using modulo, try this:
let result = [];
let returnOdd = (n1, n2) => {
for(i = n1; i < n2; i++){
if(i % 2 != 0){
result.push(i)
}
}
return result;
}
console.log(returnOdd(2, 20));
You could use the filter method.
This method creates a new array based on the condition it has. In this case it will to go through all the numbers in the array, and check if the number is odd (though the remainder operator).
For example:
1 % 2 = 1 ( true, keep in the new array )
2 % 2 = 0 ( false ignore in the new array )
function OddNumbers(start, end) {
// Create an array from the given range
const nums = Array(end - start + 1).fill().map((_, idx) => start + idx);
// Use filter to return the odd numbers via the % operator
return nums.filter(num => num % 2);
}
console.log(OddNumbers(2,20))
I am trying to solve the first question of Advent of Code 2020 in Javascript. I am tasked with finding three numbers that add to a target number. In this case, the target is 2020.
For example:
There should be three numbers: [1721, 979, 366, 299, 675, 1456] that add to 2020. In this case, those numbers are [366, 675, 979]
My approach: By Sorting the array the efficiency of the algorithm can be improved. This efficient approach uses the two-pointer technique. Traverse the array and fix the first element of the triplet. Now use the Two Pointers algorithm to find if there is a pair whose sum is equal to x – array[i]. Two pointers algorithm take linear time so it is better than a nested loop.
Algorithm: Sort the given array.
Loop over the array and fix the first element of the possible triplet, arr[i].
Then fix two pointers, one at i + 1 and the other at n – 1. And look at the sum,
If the sum is smaller than the required sum, increment the first pointer.
Else, If the sum is bigger, Decrease the end pointer to reduce the sum.
Else, if the sum of elements at two-pointer is equal to given sum then print the triplet and break.
Note: I am expanding this approach from a python thread and really like it, but while trying to create it in javascript, I am having some trouble.
Currently, this is what I have:
function threeSumBest(array, target) {
// sort elements (accending)
const sortedAsc = array.sort((a, b) => a - b)
for (let i = 0; i < sortedAsc.length; i++) {
let result = []
// index of the first element in the remaining elements
let firstElement = i + 1
// # index of the last element
let lastElement = sortedAsc.length - 1
// create a sum variable
let sum = (sortedAsc[i] + sortedAsc[firstElement] + sortedAsc[lastElement])
// console.log(sortedAsc[i], sortedAsc[firstElement], sortedAsc[lastElement], sum);
// console.log(sortedAsc[i], sortedAsc[firstElement], sortedAsc[lastElement]);
console.log(result);
if (sum > target) {
console.log('greater than');
lastElement--
}
if (sum < target) {
console.log('less than');
result[0] = sortedAsc[i++]
result[1] = sortedAsc[firstElement]
result[2] = sortedAsc[lastElement]
}
if (sum == target) {
console.log('equal');
}
}
}
console.log(threeSumBest([1721, 979, 366, 299, 675, 1456], 2020))
You're missing the inner loop to iterate on firstIndex to lastIndex.
the following code will work for you
for (let i = 0; i < sortedAsc.length; i++) {
let result = []
// index of the first element in the remaining elements
let firstElement = i + 1
// # index of the last element
let lastElement = sortedAsc.length - 1
while(firstElement<lastElement){
let sum = (sortedAsc[i] + sortedAsc[firstElement] + sortedAsc[lastElement])
if (sum > target) {
//console.log('greater than');
firstElement++;
}
if (sum < target) {
//console.log('less than');
lastElement--;
}
if (sum == target) {
result[0] = sortedAsc[i]
result[1] = sortedAsc[firstElement]
result[2] = sortedAsc[lastElement]
console.log('equal');
break;
}
}
}
console.log(threeSumBest([1721, 979, 366, 299, 675, 1456], 2020))
How can I generate some unique random numbers between 1 and 100 using JavaScript?
For example: To generate 8 unique random numbers and store them to an array, you can simply do this:
var arr = [];
while(arr.length < 8){
var r = Math.floor(Math.random() * 100) + 1;
if(arr.indexOf(r) === -1) arr.push(r);
}
console.log(arr);
Populate an array with the numbers 1 through 100.
Shuffle it.
Take the first 8 elements of the resulting array.
Modern JS Solution using Set (and average case O(n))
const nums = new Set();
while(nums.size !== 8) {
nums.add(Math.floor(Math.random() * 100) + 1);
}
console.log([...nums]);
Another approach is to generate an 100 items array with ascending numbers and sort it randomly. This leads actually to a really short and (in my opinion) simple snippet.
const numbers = Array(100).fill().map((_, index) => index + 1);
numbers.sort(() => Math.random() - 0.5);
console.log(numbers.slice(0, 8));
Generate permutation of 100 numbers and then choose serially.
Use Knuth Shuffle(aka the Fisher-Yates shuffle) Algorithm.
JavaScript:
function fisherYates ( myArray,stop_count ) {
var i = myArray.length;
if ( i == 0 ) return false;
int c = 0;
while ( --i ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tempi = myArray[i];
var tempj = myArray[j];
myArray[i] = tempj;
myArray[j] = tempi;
// Edited thanks to Frerich Raabe
c++;
if(c == stop_count)return;
}
}
CODE COPIED FROM LINK.
EDIT:
Improved code:
function fisherYates(myArray,nb_picks)
{
for (i = myArray.length-1; i > 1 ; i--)
{
var r = Math.floor(Math.random()*i);
var t = myArray[i];
myArray[i] = myArray[r];
myArray[r] = t;
}
return myArray.slice(0,nb_picks);
}
Potential problem:
Suppose we have array of 100 numbers {e.g. [1,2,3...100]} and we stop swapping after 8 swaps;
then most of the times array will look like {1,2,3,76,5,6,7,8,...numbers here will be shuffled ...10}.
Because every number will be swapped with probability 1/100 so
prob. of swapping first 8 numbers is 8/100 whereas prob. of swapping other 92 is 92/100.
But if we run algorithm for full array then we are sure (almost)every entry is swapped.
Otherwise we face a question : which 8 numbers to choose?
The above techniques are good if you want to avoid a library, but depending if you would be alright with a library, I would suggest checking out Chance for generating random stuff in JavaScript.
Specifically to solve your question, using Chance it's as easy as:
// One line!
var uniques = chance.unique(chance.natural, 8, {min: 1, max: 100});
// Print it out to the document for this snippet so we can see it in action
document.write(JSON.stringify(uniques));
<script src="http://chancejs.com/chance.min.js"></script>
Disclaimer, as the author of Chance, I am a bit biased ;)
To avoid any long and unreliable shuffles, I'd do the following...
Generate an array that contains the number between 1 and 100, in order.
Generate a random number between 1 and 100
Look up the number at this index in the array and store in your results
Remove the elemnt from the array, making it one shorter
Repeat from step 2, but use 99 as the upper limit of the random number
Repeat from step 2, but use 98 as the upper limit of the random number
Repeat from step 2, but use 97 as the upper limit of the random number
Repeat from step 2, but use 96 as the upper limit of the random number
Repeat from step 2, but use 95 as the upper limit of the random number
Repeat from step 2, but use 94 as the upper limit of the random number
Repeat from step 2, but use 93 as the upper limit of the random number
Voila - no repeated numbers.
I may post some actual code later, if anybody is interested.
Edit: It's probably the competitive streak in me but, having seen the post by #Alsciende, I couldn't resist posting the code that I promised.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>8 unique random number between 1 and 100</title>
<script type="text/javascript" language="Javascript">
function pick(n, min, max){
var values = [], i = max;
while(i >= min) values.push(i--);
var results = [];
var maxIndex = max;
for(i=1; i <= n; i++){
maxIndex--;
var index = Math.floor(maxIndex * Math.random());
results.push(values[index]);
values[index] = values[maxIndex];
}
return results;
}
function go(){
var running = true;
do{
if(!confirm(pick(8, 1, 100).sort(function(a,b){return a - b;}))){
running = false;
}
}while(running)
}
</script>
</head>
<body>
<h1>8 unique random number between 1 and 100</h1>
<p><button onclick="go()">Click me</button> to start generating numbers.</p>
<p>When the numbers appear, click OK to generate another set, or Cancel to stop.</p>
</body>
I would do this:
function randomInt(min, max) {
return Math.round(min + Math.random()*(max-min));
}
var index = {}, numbers = [];
for (var i=0; i<8; ++i) {
var number;
do {
number = randomInt(1, 100);
} while (index.hasOwnProperty("_"+number));
index["_"+number] = true;
numbers.push(number);
}
delete index;
This is a very generic function I have written to generate random unique/non-unique integers for an array. Assume the last parameter to be true in this scenario for this answer.
/* Creates an array of random integers between the range specified
len = length of the array you want to generate
min = min value you require
max = max value you require
unique = whether you want unique or not (assume 'true' for this answer)
*/
function _arrayRandom(len, min, max, unique) {
var len = (len) ? len : 10,
min = (min !== undefined) ? min : 1,
max = (max !== undefined) ? max : 100,
unique = (unique) ? unique : false,
toReturn = [], tempObj = {}, i = 0;
if(unique === true) {
for(; i < len; i++) {
var randomInt = Math.floor(Math.random() * ((max - min) + min));
if(tempObj['key_'+ randomInt] === undefined) {
tempObj['key_'+ randomInt] = randomInt;
toReturn.push(randomInt);
} else {
i--;
}
}
} else {
for(; i < len; i++) {
toReturn.push(Math.floor(Math.random() * ((max - min) + min)));
}
}
return toReturn;
}
Here the 'tempObj' is a very useful obj since every random number generated will directly check in this tempObj if that key already exists, if not, then we reduce the i by one since we need 1 extra run since the current random number already exists.
In your case, run the following
_arrayRandom(8, 1, 100, true);
That's all.
Shuffling the numbers from 1 to 100 is the right basic strategy, but if you need only 8 shuffled numbers, there's no need to shuffle all 100 numbers.
I don't know Javascript very well, but I believe it's easy to create an array of 100 nulls quickly. Then, for 8 rounds, you swap the n'th element of the array (n starting at 0) with a randomly selected element from n+1 through 99. Of course, any elements not populated yet mean that the element would really have been the original index plus 1, so that's trivial to factor in. When you're done with the 8 rounds, the first 8 elements of your array will have your 8 shuffled numbers.
var arr = []
while(arr.length < 8){
var randomnumber=Math.ceil(Math.random()*100)
if(arr.indexOf(randomnumber) === -1){arr.push(randomnumber)}
}
document.write(arr);
shorter than other answers I've seen
Implementing this as a generator makes it pretty nice to work with. Note, this implementation differs from ones that require the entire input array to be shuffled first.
This sample function works lazily, giving you 1 random item per iteration up to N items you ask for. This is nice because if you just want 3 items from a list of 1000, you don't have to touch all 1000 items first.
// sample :: Integer -> [a] -> [a]
const sample = n => function* (xs) {
let ys = xs.slice(0);
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield ys.splice(i,1)[0];
n--; len--;
}
}
// example inputs
let items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// get 3 random items
for (let i of sample(3) (items))
console.log(i); // f g c
// partial application
const lotto = sample(3);
for (let i of lotto(numbers))
console.log(i); // 3 8 7
// shuffle an array
const shuffle = xs => Array.from(sample (Infinity) (xs))
console.log(shuffle(items)) // [b c g f d e a]
I chose to implement sample in a way that does not mutate the input array, but you could easily argue that a mutating implementation is favourable.
For example, the shuffle function might wish to mutate the original input array. Or you might wish to sample from the same input at various times, updating the input each time.
// sample :: Integer -> [a] -> [a]
const sample = n => function* (xs) {
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield xs.splice(i,1)[0];
n--; len--;
}
}
// deal :: [Card] -> [Card]
const deal = xs => Array.from(sample (2) (xs));
// setup a deck of cards (13 in this case)
// cards :: [Card]
let cards = 'A234567890JQK'.split('');
// deal 6 players 2 cards each
// players :: [[Card]]
let players = Array.from(Array(6), $=> deal(cards))
console.log(players);
// [K, J], [6, 0], [2, 8], [Q, 7], [5, 4], [9, A]
// `cards` has been mutated. only 1 card remains in the deck
console.log(cards);
// [3]
sample is no longer a pure function because of the array input mutation, but in certain circumstances (demonstrated above) it might make more sense.
Another reason I chose a generator instead of a function that just returns an array is because you may want to continue sampling until some specific condition.
Perhaps I want the first prime number from a list of 1,000,000 random numbers.
"How many should I sample?" – you don't have to specify
"Do I have to find all the primes first and then select a random prime?" – Nope.
Because we're working with a generator, this task is trivial
const randomPrimeNumber = listOfNumbers => {
for (let x of sample(Infinity) (listOfNumbers)) {
if (isPrime(x))
return x;
}
return NaN;
}
This will continuously sample 1 random number at a time, x, check if it's prime, then return x if it is. If the list of numbers is exhausted before a prime is found, NaN is returned.
Note:
This answer was originally shared on another question that was closed as a duplicate of this one. Because it's very different from the other solutions provided here, I've decided to share it here as well
var numbers = [];
for (let i = 0; i < 8; i++) {
let a = true,
n;
while(a) {
n = Math.floor(Math.random() * 100) + 1;
a = numbers.includes(n);
}
numbers.push(n);
}
console.log(numbers);
Same permutation algorithm as The Machine Charmer, but with a prototyped implementation. Better suited to large number of picks. Uses js 1.7 destructuring assignment if available.
// swaps elements at index i and j in array this
// swapping is easy on js 1.7 (feature detection)
Array.prototype.swap = (function () {
var i=0, j=1;
try { [i,j]=[j,i]; }
catch (e) {}
if(i) {
return function(i,j) {
[this[i],this[j]] = [this[j],this[i]];
return this;
}
} else {
return function(i,j) {
var temp = this[i];
this[i] = this[j];
this[j] = temp;
return this;
}
}
})();
// shuffles array this
Array.prototype.shuffle = function() {
for(var i=this.length; i>1; i--) {
this.swap(i-1, Math.floor(i*Math.random()));
}
return this;
}
// returns n unique random numbers between min and max
function pick(n, min, max) {
var a = [], i = max;
while(i >= min) a.push(i--);
return a.shuffle().slice(0,n);
}
pick(8,1,100);
Edit:
An other proposition, better suited to small number of picks, based on belugabob's answer. To guarantee uniqueness, we remove the picked numbers from the array.
// removes n random elements from array this
// and returns them
Array.prototype.pick = function(n) {
if(!n || !this.length) return [];
var i = Math.floor(this.length*Math.random());
return this.splice(i,1).concat(this.pick(n-1));
}
// returns n unique random numbers between min and max
function pick(n, min, max) {
var a = [], i = max;
while(i >= min) a.push(i--);
return a.pick(n);
}
pick(8,1,100);
for arrays with holes like this [,2,,4,,6,7,,]
because my problem was to fill these holes. So I modified it as per my need :)
the following modified solution worked for me :)
var arr = [,2,,4,,6,7,,]; //example
while(arr.length < 9){
var randomnumber=Math.floor(Math.random()*9+1);
var found=false;
for(var i=0;i<arr.length;i++){
if(arr[i]==randomnumber){found=true;break;}
}
if(!found)
for(k=0;k<9;k++)
{if(!arr[k]) //if it's empty !!MODIFICATION
{arr[k]=randomnumber; break;}}
}
alert(arr); //outputs on the screen
The best earlier answer is the answer by sje397. You will get as good random numbers as you can get, as quick as possible.
My solution is very similar to his solution. However, sometimes you want the random numbers in random order, and that is why I decided to post an answer. In addition, I provide a general function.
function selectKOutOfN(k, n) {
if (k>n) throw "k>n";
var selection = [];
var sorted = [];
for (var i = 0; i < k; i++) {
var rand = Math.floor(Math.random()*(n - i));
for (var j = 0; j < i; j++) {
if (sorted[j]<=rand)
rand++;
else
break;
}
selection.push(rand);
sorted.splice(j, 0, rand);
}
return selection;
}
alert(selectKOutOfN(8, 100));
Here is my ES6 version I cobbled together. I'm sure it can be a little more consolidated.
function randomArray(i, min, max) {
min = Math.ceil(min);
max = Math.floor(max);
let arr = Array.from({length: i}, () => Math.floor(Math.random()* (max - min)) + min);
return arr.sort();
}
let uniqueItems = [...new Set(randomArray(8, 0, 100))]
console.log(uniqueItems);
How about using object properties as a hash table? This way your best scenario is to only randomize 8 times. It would only be effective if you want a small part of the range of numbers. It's also much less memory intensive than Fisher-Yates because you don't have to allocate space for an array.
var ht={}, i=rands=8;
while ( i>0 || keys(ht).length<rands) ht[Math.ceil(Math.random()*100)]=i--;
alert(keys(ht));
I then found out that Object.keys(obj) is an ECMAScript 5 feature so the above is pretty much useless on the internets right now. Fear not, because I made it ECMAScript 3 compatible by adding a keys function like this.
if (typeof keys == "undefined")
{
var keys = function(obj)
{
props=[];
for (k in ht) if (ht.hasOwnProperty(k)) props.push(k);
return props;
}
}
var bombout=0;
var checkArr=[];
var arr=[];
while(arr.length < 8 && bombout<100){
bombout++;
var randomNumber=Math.ceil(Math.random()*100);
if(typeof checkArr[randomNumber] == "undefined"){
checkArr[randomNumber]=1;
arr.push(randomNumber);
}
}
// untested - hence bombout
if you need more unique you must generate a array(1..100).
var arr=[];
function generateRandoms(){
for(var i=1;i<=100;i++) arr.push(i);
}
function extractUniqueRandom()
{
if (arr.length==0) generateRandoms();
var randIndex=Math.floor(arr.length*Math.random());
var result=arr[randIndex];
arr.splice(randIndex,1);
return result;
}
function extractUniqueRandomArray(n)
{
var resultArr=[];
for(var i=0;i<n;i++) resultArr.push(extractUniqueRandom());
return resultArr;
}
above code is faster:
extractUniqueRandomArray(50)=>
[2, 79, 38, 59, 63, 42, 52, 22, 78, 50, 39, 77, 1, 88, 40, 23, 48, 84, 91, 49, 4, 54, 93, 36, 100, 82, 62, 41, 89, 12, 24, 31, 86, 92, 64, 75, 70, 61, 67, 98, 76, 80, 56, 90, 83, 44, 43, 47, 7, 53]
Adding another better version of same code (accepted answer) with JavaScript 1.6 indexOf function. Do not need to loop thru whole array every time you are checking the duplicate.
var arr = []
while(arr.length < 8){
var randomnumber=Math.ceil(Math.random()*100)
var found=false;
if(arr.indexOf(randomnumber) > -1){found=true;}
if(!found)arr[arr.length]=randomnumber;
}
Older version of Javascript can still use the version at top
PS: Tried suggesting an update to the wiki but it was rejected. I still think it may be useful for others.
This is my personal solution :
<script>
var i, k;
var numbers = new Array();
k = Math.floor((Math.random()*8));
numbers[0]=k;
for (var j=1;j<8;j++){
k = Math.floor((Math.random()*8));
i=0;
while (i < numbers.length){
if (numbers[i] == k){
k = Math.floor((Math.random()*8));
i=0;
}else {i++;}
}
numbers[j]=k;
}
for (var j=0;j<8;j++){
alert (numbers[j]);
}
</script>
It randomly generates 8 unique array values (between 0 and 7), then displays them using an alert box.
function getUniqueRandomNos() {
var indexedArrayOfRandomNo = [];
for (var i = 0; i < 100; i++) {
var randNo = Math.random();
indexedArrayOfRandomNo.push([i, randNo]);
}
indexedArrayOfRandomNo.sort(function (arr1, arr2) {
return arr1[1] - arr2[1]
});
var uniqueRandNoArray = [];
for (i = 0; i < 8; i++) {
uniqueRandNoArray.push(indexedArrayOfRandomNo[i][0]);
}
return uniqueRandNoArray;
}
I think this method is different from methods given in most of the answers, so I thought I might add an answer here (though the question was asked 4 years ago).
We generate 100 random numbers, and tag each of them with numbers from 1 to 100. Then we sort these tagged random numbers, and the tags get shuffled randomly. Alternatively, as needed in this question, one could do away with just finding top 8 of the tagged random numbers. Finding top 8 items is cheaper than sorting the whole array.
One must note here, that the sorting algorithm influences this algorithm. If the sorting algorithm used is stable, there is slight bias in favor of smaller numbers. Ideally, we would want the sorting algorithm to be unstable and not even biased towards stability (or instability) to produce an answer with perfectly uniform probability distribution.
This can handle generating upto 20 digit UNIQUE random number
JS
var generatedNumbers = [];
function generateRandomNumber(precision) { // input --> number precision in integer
if (precision <= 20) {
var randomNum = Math.round(Math.random().toFixed(precision) * Math.pow(10, precision));
if (generatedNumbers.indexOf(randomNum) > -1) {
if (generatedNumbers.length == Math.pow(10, precision))
return "Generated all values with this precision";
return generateRandomNumber(precision);
} else {
generatedNumbers.push(randomNum);
return randomNum;
}
} else
return "Number Precision shoould not exceed 20";
}
generateRandomNumber(1);
jsFiddle
This solution uses the hash which is much more performant O(1) than checking if the resides in the array. It has extra safe checks too. Hope it helps.
function uniqueArray(minRange, maxRange, arrayLength) {
var arrayLength = (arrayLength) ? arrayLength : 10
var minRange = (minRange !== undefined) ? minRange : 1
var maxRange = (maxRange !== undefined) ? maxRange : 100
var numberOfItemsInArray = 0
var hash = {}
var array = []
if ( arrayLength > (maxRange - minRange) ) throw new Error('Cannot generate unique array: Array length too high')
while(numberOfItemsInArray < arrayLength){
// var randomNumber = Math.floor(Math.random() * (maxRange - minRange + 1) + minRange)
// following line used for performance benefits
var randomNumber = (Math.random() * (maxRange - minRange + 1) + minRange) << 0
if (!hash[randomNumber]) {
hash[randomNumber] = true
array.push(randomNumber)
numberOfItemsInArray++
}
}
return array
}
document.write(uniqueArray(1, 100, 8))
You can also do it with a one liner like this:
[...((add, set) => add(set, add))((set, add) => set.size < 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]
getRandom (min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
getNRandom (min, max, n) {
const numbers = []
if (min > max) {
return new Error('Max is gt min')
}
if (min === max) {
return [min]
}
if ((max - min) >= n) {
while (numbers.length < n) {
let rand = this.getRandom(min, max + 1)
if (numbers.indexOf(rand) === -1) {
numbers.push(rand)
}
}
}
if ((max - min) < n) {
for (let i = min; i <= max; i++) {
numbers.push(i)
}
}
return numbers
}
Using a Set is your fastest option. Here is a generic function for getting a unique random that uses a callback generator. Now it's fast and reusable.
// Get a unique 'anything'
let unique = new Set()
function getUnique(generator) {
let number = generator()
while (!unique.add(number)) {
number = generator()
}
return number;
}
// The generator. Return anything, not just numbers.
const between_1_100 = () => 1 + Math.floor(Math.random() * 100)
// Test it
for (var i = 0; i < 8; i++) {
const aNumber = getUnique(between_1_100)
}
// Dump the 'stored numbers'
console.log(Array.from(unique))
This is a implementation of Fisher Yates/Durstenfeld Shuffle, but without actual creation of a array thus reducing space complexity or memory needed, when the pick size is small compared to the number of elements available.
To pick 8 numbers from 100, it is not necessary to create a array of 100 elements.
Assuming a array is created,
From the end of array(100), get random number(rnd) from 1 to 100
Swap 100 and the random number rnd
Repeat step 1 with array(99)
If a array is not created, A hashMap may be used to remember the actual swapped positions. When the second random number generated is equal to the one of the previously generated numbers, the map provides the current value in that position rather than the actual value.
const getRandom_ = (start, end) => {
return Math.floor(Math.random() * (end - start + 1)) + start;
};
const getRealValue_ = (map, rnd) => {
if (map.has(rnd)) {
return getRealValue_(map, map.get(rnd));
} else {
return rnd;
}
};
const getRandomNumbers = (n, start, end) => {
const out = new Map();
while (n--) {
const rnd = getRandom_(start, end--);
out.set(getRealValue_(out, rnd), end + 1);
}
return [...out.keys()];
};
console.info(getRandomNumbers(8, 1, 100));
console.info(getRandomNumbers(8, 1, Math.pow(10, 12)));
console.info(getRandomNumbers(800000, 1, Math.pow(10, 15)));
Here is an example of random 5 numbers taken from a range of 0 to 100 (both 0 and 100 included) with no duplication.
let finals = [];
const count = 5; // Considering 5 numbers
const max = 100;
for(let i = 0; i < max; i++){
const rand = Math.round(Math.random() * max);
!finals.includes(rand) && finals.push(rand)
}
finals = finals.slice(0, count)
How can I generate some unique random numbers between 1 and 100 using JavaScript?
For example: To generate 8 unique random numbers and store them to an array, you can simply do this:
var arr = [];
while(arr.length < 8){
var r = Math.floor(Math.random() * 100) + 1;
if(arr.indexOf(r) === -1) arr.push(r);
}
console.log(arr);
Populate an array with the numbers 1 through 100.
Shuffle it.
Take the first 8 elements of the resulting array.
Modern JS Solution using Set (and average case O(n))
const nums = new Set();
while(nums.size !== 8) {
nums.add(Math.floor(Math.random() * 100) + 1);
}
console.log([...nums]);
Another approach is to generate an 100 items array with ascending numbers and sort it randomly. This leads actually to a really short and (in my opinion) simple snippet.
const numbers = Array(100).fill().map((_, index) => index + 1);
numbers.sort(() => Math.random() - 0.5);
console.log(numbers.slice(0, 8));
Generate permutation of 100 numbers and then choose serially.
Use Knuth Shuffle(aka the Fisher-Yates shuffle) Algorithm.
JavaScript:
function fisherYates ( myArray,stop_count ) {
var i = myArray.length;
if ( i == 0 ) return false;
int c = 0;
while ( --i ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tempi = myArray[i];
var tempj = myArray[j];
myArray[i] = tempj;
myArray[j] = tempi;
// Edited thanks to Frerich Raabe
c++;
if(c == stop_count)return;
}
}
CODE COPIED FROM LINK.
EDIT:
Improved code:
function fisherYates(myArray,nb_picks)
{
for (i = myArray.length-1; i > 1 ; i--)
{
var r = Math.floor(Math.random()*i);
var t = myArray[i];
myArray[i] = myArray[r];
myArray[r] = t;
}
return myArray.slice(0,nb_picks);
}
Potential problem:
Suppose we have array of 100 numbers {e.g. [1,2,3...100]} and we stop swapping after 8 swaps;
then most of the times array will look like {1,2,3,76,5,6,7,8,...numbers here will be shuffled ...10}.
Because every number will be swapped with probability 1/100 so
prob. of swapping first 8 numbers is 8/100 whereas prob. of swapping other 92 is 92/100.
But if we run algorithm for full array then we are sure (almost)every entry is swapped.
Otherwise we face a question : which 8 numbers to choose?
The above techniques are good if you want to avoid a library, but depending if you would be alright with a library, I would suggest checking out Chance for generating random stuff in JavaScript.
Specifically to solve your question, using Chance it's as easy as:
// One line!
var uniques = chance.unique(chance.natural, 8, {min: 1, max: 100});
// Print it out to the document for this snippet so we can see it in action
document.write(JSON.stringify(uniques));
<script src="http://chancejs.com/chance.min.js"></script>
Disclaimer, as the author of Chance, I am a bit biased ;)
To avoid any long and unreliable shuffles, I'd do the following...
Generate an array that contains the number between 1 and 100, in order.
Generate a random number between 1 and 100
Look up the number at this index in the array and store in your results
Remove the elemnt from the array, making it one shorter
Repeat from step 2, but use 99 as the upper limit of the random number
Repeat from step 2, but use 98 as the upper limit of the random number
Repeat from step 2, but use 97 as the upper limit of the random number
Repeat from step 2, but use 96 as the upper limit of the random number
Repeat from step 2, but use 95 as the upper limit of the random number
Repeat from step 2, but use 94 as the upper limit of the random number
Repeat from step 2, but use 93 as the upper limit of the random number
Voila - no repeated numbers.
I may post some actual code later, if anybody is interested.
Edit: It's probably the competitive streak in me but, having seen the post by #Alsciende, I couldn't resist posting the code that I promised.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>8 unique random number between 1 and 100</title>
<script type="text/javascript" language="Javascript">
function pick(n, min, max){
var values = [], i = max;
while(i >= min) values.push(i--);
var results = [];
var maxIndex = max;
for(i=1; i <= n; i++){
maxIndex--;
var index = Math.floor(maxIndex * Math.random());
results.push(values[index]);
values[index] = values[maxIndex];
}
return results;
}
function go(){
var running = true;
do{
if(!confirm(pick(8, 1, 100).sort(function(a,b){return a - b;}))){
running = false;
}
}while(running)
}
</script>
</head>
<body>
<h1>8 unique random number between 1 and 100</h1>
<p><button onclick="go()">Click me</button> to start generating numbers.</p>
<p>When the numbers appear, click OK to generate another set, or Cancel to stop.</p>
</body>
I would do this:
function randomInt(min, max) {
return Math.round(min + Math.random()*(max-min));
}
var index = {}, numbers = [];
for (var i=0; i<8; ++i) {
var number;
do {
number = randomInt(1, 100);
} while (index.hasOwnProperty("_"+number));
index["_"+number] = true;
numbers.push(number);
}
delete index;
This is a very generic function I have written to generate random unique/non-unique integers for an array. Assume the last parameter to be true in this scenario for this answer.
/* Creates an array of random integers between the range specified
len = length of the array you want to generate
min = min value you require
max = max value you require
unique = whether you want unique or not (assume 'true' for this answer)
*/
function _arrayRandom(len, min, max, unique) {
var len = (len) ? len : 10,
min = (min !== undefined) ? min : 1,
max = (max !== undefined) ? max : 100,
unique = (unique) ? unique : false,
toReturn = [], tempObj = {}, i = 0;
if(unique === true) {
for(; i < len; i++) {
var randomInt = Math.floor(Math.random() * ((max - min) + min));
if(tempObj['key_'+ randomInt] === undefined) {
tempObj['key_'+ randomInt] = randomInt;
toReturn.push(randomInt);
} else {
i--;
}
}
} else {
for(; i < len; i++) {
toReturn.push(Math.floor(Math.random() * ((max - min) + min)));
}
}
return toReturn;
}
Here the 'tempObj' is a very useful obj since every random number generated will directly check in this tempObj if that key already exists, if not, then we reduce the i by one since we need 1 extra run since the current random number already exists.
In your case, run the following
_arrayRandom(8, 1, 100, true);
That's all.
Shuffling the numbers from 1 to 100 is the right basic strategy, but if you need only 8 shuffled numbers, there's no need to shuffle all 100 numbers.
I don't know Javascript very well, but I believe it's easy to create an array of 100 nulls quickly. Then, for 8 rounds, you swap the n'th element of the array (n starting at 0) with a randomly selected element from n+1 through 99. Of course, any elements not populated yet mean that the element would really have been the original index plus 1, so that's trivial to factor in. When you're done with the 8 rounds, the first 8 elements of your array will have your 8 shuffled numbers.
var arr = []
while(arr.length < 8){
var randomnumber=Math.ceil(Math.random()*100)
if(arr.indexOf(randomnumber) === -1){arr.push(randomnumber)}
}
document.write(arr);
shorter than other answers I've seen
Implementing this as a generator makes it pretty nice to work with. Note, this implementation differs from ones that require the entire input array to be shuffled first.
This sample function works lazily, giving you 1 random item per iteration up to N items you ask for. This is nice because if you just want 3 items from a list of 1000, you don't have to touch all 1000 items first.
// sample :: Integer -> [a] -> [a]
const sample = n => function* (xs) {
let ys = xs.slice(0);
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield ys.splice(i,1)[0];
n--; len--;
}
}
// example inputs
let items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// get 3 random items
for (let i of sample(3) (items))
console.log(i); // f g c
// partial application
const lotto = sample(3);
for (let i of lotto(numbers))
console.log(i); // 3 8 7
// shuffle an array
const shuffle = xs => Array.from(sample (Infinity) (xs))
console.log(shuffle(items)) // [b c g f d e a]
I chose to implement sample in a way that does not mutate the input array, but you could easily argue that a mutating implementation is favourable.
For example, the shuffle function might wish to mutate the original input array. Or you might wish to sample from the same input at various times, updating the input each time.
// sample :: Integer -> [a] -> [a]
const sample = n => function* (xs) {
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield xs.splice(i,1)[0];
n--; len--;
}
}
// deal :: [Card] -> [Card]
const deal = xs => Array.from(sample (2) (xs));
// setup a deck of cards (13 in this case)
// cards :: [Card]
let cards = 'A234567890JQK'.split('');
// deal 6 players 2 cards each
// players :: [[Card]]
let players = Array.from(Array(6), $=> deal(cards))
console.log(players);
// [K, J], [6, 0], [2, 8], [Q, 7], [5, 4], [9, A]
// `cards` has been mutated. only 1 card remains in the deck
console.log(cards);
// [3]
sample is no longer a pure function because of the array input mutation, but in certain circumstances (demonstrated above) it might make more sense.
Another reason I chose a generator instead of a function that just returns an array is because you may want to continue sampling until some specific condition.
Perhaps I want the first prime number from a list of 1,000,000 random numbers.
"How many should I sample?" – you don't have to specify
"Do I have to find all the primes first and then select a random prime?" – Nope.
Because we're working with a generator, this task is trivial
const randomPrimeNumber = listOfNumbers => {
for (let x of sample(Infinity) (listOfNumbers)) {
if (isPrime(x))
return x;
}
return NaN;
}
This will continuously sample 1 random number at a time, x, check if it's prime, then return x if it is. If the list of numbers is exhausted before a prime is found, NaN is returned.
Note:
This answer was originally shared on another question that was closed as a duplicate of this one. Because it's very different from the other solutions provided here, I've decided to share it here as well
var numbers = [];
for (let i = 0; i < 8; i++) {
let a = true,
n;
while(a) {
n = Math.floor(Math.random() * 100) + 1;
a = numbers.includes(n);
}
numbers.push(n);
}
console.log(numbers);
Same permutation algorithm as The Machine Charmer, but with a prototyped implementation. Better suited to large number of picks. Uses js 1.7 destructuring assignment if available.
// swaps elements at index i and j in array this
// swapping is easy on js 1.7 (feature detection)
Array.prototype.swap = (function () {
var i=0, j=1;
try { [i,j]=[j,i]; }
catch (e) {}
if(i) {
return function(i,j) {
[this[i],this[j]] = [this[j],this[i]];
return this;
}
} else {
return function(i,j) {
var temp = this[i];
this[i] = this[j];
this[j] = temp;
return this;
}
}
})();
// shuffles array this
Array.prototype.shuffle = function() {
for(var i=this.length; i>1; i--) {
this.swap(i-1, Math.floor(i*Math.random()));
}
return this;
}
// returns n unique random numbers between min and max
function pick(n, min, max) {
var a = [], i = max;
while(i >= min) a.push(i--);
return a.shuffle().slice(0,n);
}
pick(8,1,100);
Edit:
An other proposition, better suited to small number of picks, based on belugabob's answer. To guarantee uniqueness, we remove the picked numbers from the array.
// removes n random elements from array this
// and returns them
Array.prototype.pick = function(n) {
if(!n || !this.length) return [];
var i = Math.floor(this.length*Math.random());
return this.splice(i,1).concat(this.pick(n-1));
}
// returns n unique random numbers between min and max
function pick(n, min, max) {
var a = [], i = max;
while(i >= min) a.push(i--);
return a.pick(n);
}
pick(8,1,100);
for arrays with holes like this [,2,,4,,6,7,,]
because my problem was to fill these holes. So I modified it as per my need :)
the following modified solution worked for me :)
var arr = [,2,,4,,6,7,,]; //example
while(arr.length < 9){
var randomnumber=Math.floor(Math.random()*9+1);
var found=false;
for(var i=0;i<arr.length;i++){
if(arr[i]==randomnumber){found=true;break;}
}
if(!found)
for(k=0;k<9;k++)
{if(!arr[k]) //if it's empty !!MODIFICATION
{arr[k]=randomnumber; break;}}
}
alert(arr); //outputs on the screen
The best earlier answer is the answer by sje397. You will get as good random numbers as you can get, as quick as possible.
My solution is very similar to his solution. However, sometimes you want the random numbers in random order, and that is why I decided to post an answer. In addition, I provide a general function.
function selectKOutOfN(k, n) {
if (k>n) throw "k>n";
var selection = [];
var sorted = [];
for (var i = 0; i < k; i++) {
var rand = Math.floor(Math.random()*(n - i));
for (var j = 0; j < i; j++) {
if (sorted[j]<=rand)
rand++;
else
break;
}
selection.push(rand);
sorted.splice(j, 0, rand);
}
return selection;
}
alert(selectKOutOfN(8, 100));
Here is my ES6 version I cobbled together. I'm sure it can be a little more consolidated.
function randomArray(i, min, max) {
min = Math.ceil(min);
max = Math.floor(max);
let arr = Array.from({length: i}, () => Math.floor(Math.random()* (max - min)) + min);
return arr.sort();
}
let uniqueItems = [...new Set(randomArray(8, 0, 100))]
console.log(uniqueItems);
How about using object properties as a hash table? This way your best scenario is to only randomize 8 times. It would only be effective if you want a small part of the range of numbers. It's also much less memory intensive than Fisher-Yates because you don't have to allocate space for an array.
var ht={}, i=rands=8;
while ( i>0 || keys(ht).length<rands) ht[Math.ceil(Math.random()*100)]=i--;
alert(keys(ht));
I then found out that Object.keys(obj) is an ECMAScript 5 feature so the above is pretty much useless on the internets right now. Fear not, because I made it ECMAScript 3 compatible by adding a keys function like this.
if (typeof keys == "undefined")
{
var keys = function(obj)
{
props=[];
for (k in ht) if (ht.hasOwnProperty(k)) props.push(k);
return props;
}
}
var bombout=0;
var checkArr=[];
var arr=[];
while(arr.length < 8 && bombout<100){
bombout++;
var randomNumber=Math.ceil(Math.random()*100);
if(typeof checkArr[randomNumber] == "undefined"){
checkArr[randomNumber]=1;
arr.push(randomNumber);
}
}
// untested - hence bombout
if you need more unique you must generate a array(1..100).
var arr=[];
function generateRandoms(){
for(var i=1;i<=100;i++) arr.push(i);
}
function extractUniqueRandom()
{
if (arr.length==0) generateRandoms();
var randIndex=Math.floor(arr.length*Math.random());
var result=arr[randIndex];
arr.splice(randIndex,1);
return result;
}
function extractUniqueRandomArray(n)
{
var resultArr=[];
for(var i=0;i<n;i++) resultArr.push(extractUniqueRandom());
return resultArr;
}
above code is faster:
extractUniqueRandomArray(50)=>
[2, 79, 38, 59, 63, 42, 52, 22, 78, 50, 39, 77, 1, 88, 40, 23, 48, 84, 91, 49, 4, 54, 93, 36, 100, 82, 62, 41, 89, 12, 24, 31, 86, 92, 64, 75, 70, 61, 67, 98, 76, 80, 56, 90, 83, 44, 43, 47, 7, 53]
Adding another better version of same code (accepted answer) with JavaScript 1.6 indexOf function. Do not need to loop thru whole array every time you are checking the duplicate.
var arr = []
while(arr.length < 8){
var randomnumber=Math.ceil(Math.random()*100)
var found=false;
if(arr.indexOf(randomnumber) > -1){found=true;}
if(!found)arr[arr.length]=randomnumber;
}
Older version of Javascript can still use the version at top
PS: Tried suggesting an update to the wiki but it was rejected. I still think it may be useful for others.
This is my personal solution :
<script>
var i, k;
var numbers = new Array();
k = Math.floor((Math.random()*8));
numbers[0]=k;
for (var j=1;j<8;j++){
k = Math.floor((Math.random()*8));
i=0;
while (i < numbers.length){
if (numbers[i] == k){
k = Math.floor((Math.random()*8));
i=0;
}else {i++;}
}
numbers[j]=k;
}
for (var j=0;j<8;j++){
alert (numbers[j]);
}
</script>
It randomly generates 8 unique array values (between 0 and 7), then displays them using an alert box.
function getUniqueRandomNos() {
var indexedArrayOfRandomNo = [];
for (var i = 0; i < 100; i++) {
var randNo = Math.random();
indexedArrayOfRandomNo.push([i, randNo]);
}
indexedArrayOfRandomNo.sort(function (arr1, arr2) {
return arr1[1] - arr2[1]
});
var uniqueRandNoArray = [];
for (i = 0; i < 8; i++) {
uniqueRandNoArray.push(indexedArrayOfRandomNo[i][0]);
}
return uniqueRandNoArray;
}
I think this method is different from methods given in most of the answers, so I thought I might add an answer here (though the question was asked 4 years ago).
We generate 100 random numbers, and tag each of them with numbers from 1 to 100. Then we sort these tagged random numbers, and the tags get shuffled randomly. Alternatively, as needed in this question, one could do away with just finding top 8 of the tagged random numbers. Finding top 8 items is cheaper than sorting the whole array.
One must note here, that the sorting algorithm influences this algorithm. If the sorting algorithm used is stable, there is slight bias in favor of smaller numbers. Ideally, we would want the sorting algorithm to be unstable and not even biased towards stability (or instability) to produce an answer with perfectly uniform probability distribution.
This can handle generating upto 20 digit UNIQUE random number
JS
var generatedNumbers = [];
function generateRandomNumber(precision) { // input --> number precision in integer
if (precision <= 20) {
var randomNum = Math.round(Math.random().toFixed(precision) * Math.pow(10, precision));
if (generatedNumbers.indexOf(randomNum) > -1) {
if (generatedNumbers.length == Math.pow(10, precision))
return "Generated all values with this precision";
return generateRandomNumber(precision);
} else {
generatedNumbers.push(randomNum);
return randomNum;
}
} else
return "Number Precision shoould not exceed 20";
}
generateRandomNumber(1);
jsFiddle
This solution uses the hash which is much more performant O(1) than checking if the resides in the array. It has extra safe checks too. Hope it helps.
function uniqueArray(minRange, maxRange, arrayLength) {
var arrayLength = (arrayLength) ? arrayLength : 10
var minRange = (minRange !== undefined) ? minRange : 1
var maxRange = (maxRange !== undefined) ? maxRange : 100
var numberOfItemsInArray = 0
var hash = {}
var array = []
if ( arrayLength > (maxRange - minRange) ) throw new Error('Cannot generate unique array: Array length too high')
while(numberOfItemsInArray < arrayLength){
// var randomNumber = Math.floor(Math.random() * (maxRange - minRange + 1) + minRange)
// following line used for performance benefits
var randomNumber = (Math.random() * (maxRange - minRange + 1) + minRange) << 0
if (!hash[randomNumber]) {
hash[randomNumber] = true
array.push(randomNumber)
numberOfItemsInArray++
}
}
return array
}
document.write(uniqueArray(1, 100, 8))
You can also do it with a one liner like this:
[...((add, set) => add(set, add))((set, add) => set.size < 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]
getRandom (min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
getNRandom (min, max, n) {
const numbers = []
if (min > max) {
return new Error('Max is gt min')
}
if (min === max) {
return [min]
}
if ((max - min) >= n) {
while (numbers.length < n) {
let rand = this.getRandom(min, max + 1)
if (numbers.indexOf(rand) === -1) {
numbers.push(rand)
}
}
}
if ((max - min) < n) {
for (let i = min; i <= max; i++) {
numbers.push(i)
}
}
return numbers
}
Using a Set is your fastest option. Here is a generic function for getting a unique random that uses a callback generator. Now it's fast and reusable.
// Get a unique 'anything'
let unique = new Set()
function getUnique(generator) {
let number = generator()
while (!unique.add(number)) {
number = generator()
}
return number;
}
// The generator. Return anything, not just numbers.
const between_1_100 = () => 1 + Math.floor(Math.random() * 100)
// Test it
for (var i = 0; i < 8; i++) {
const aNumber = getUnique(between_1_100)
}
// Dump the 'stored numbers'
console.log(Array.from(unique))
This is a implementation of Fisher Yates/Durstenfeld Shuffle, but without actual creation of a array thus reducing space complexity or memory needed, when the pick size is small compared to the number of elements available.
To pick 8 numbers from 100, it is not necessary to create a array of 100 elements.
Assuming a array is created,
From the end of array(100), get random number(rnd) from 1 to 100
Swap 100 and the random number rnd
Repeat step 1 with array(99)
If a array is not created, A hashMap may be used to remember the actual swapped positions. When the second random number generated is equal to the one of the previously generated numbers, the map provides the current value in that position rather than the actual value.
const getRandom_ = (start, end) => {
return Math.floor(Math.random() * (end - start + 1)) + start;
};
const getRealValue_ = (map, rnd) => {
if (map.has(rnd)) {
return getRealValue_(map, map.get(rnd));
} else {
return rnd;
}
};
const getRandomNumbers = (n, start, end) => {
const out = new Map();
while (n--) {
const rnd = getRandom_(start, end--);
out.set(getRealValue_(out, rnd), end + 1);
}
return [...out.keys()];
};
console.info(getRandomNumbers(8, 1, 100));
console.info(getRandomNumbers(8, 1, Math.pow(10, 12)));
console.info(getRandomNumbers(800000, 1, Math.pow(10, 15)));
Here is an example of random 5 numbers taken from a range of 0 to 100 (both 0 and 100 included) with no duplication.
let finals = [];
const count = 5; // Considering 5 numbers
const max = 100;
for(let i = 0; i < max; i++){
const rand = Math.round(Math.random() * max);
!finals.includes(rand) && finals.push(rand)
}
finals = finals.slice(0, count)