How to choose randomly unique number when the button is clicked - javascript

I am trying to choose random unique numbers everytime when I click button. For this my function is:
const chooseNumber = () => {
var r = Math.floor(Math.random() * 75) + 1;
console.log(r)
while(selectedNumbers.indexOf(r) === -1) {
selectedNumbers.push(r);
}
console.log(selectedNumbers);
};
But the problem is if the random number is already on my list, I need to click the button again to generate new number and it goes until it find the number which is not on the list. But I want to generate number which is not on the list directly so I dont need to click the button everytime. Thanks for you helps.

You are in a right track, except the while loop should be for random number generator, not pushing number into an array:
const selectedNumbers = [];
const chooseNumber = () => {
let r;
do
{
r = Math.floor(Math.random() * 75) + 1;
}
while(selectedNumbers.indexOf(r) > -1)
selectedNumbers.push(r);
console.log(r, "["+selectedNumbers+"]");
};
<button onclick="chooseNumber()">Generate</button>
Note, that this might eventually lead to a freeze, since there is no fail safe check if array is full, so to battle that we should also check length of the array:
const selectedNumbers = [];
const maxNumber = 75;
const chooseNumber = () => {
let r;
do
{
r = ~~(Math.random() * maxNumber) + 1;
}
while(selectedNumbers.indexOf(r) > -1 && selectedNumbers.length < maxNumber)
if (selectedNumbers.length < maxNumber)
selectedNumbers.push(r);
else
console.log("array is full");
console.log(r, "["+selectedNumbers+"]");
};
for(let i = 0; i < 76; i++)
{
chooseNumber();
}
<button onclick="chooseNumber()">Generate</button>

Don't rely on a loop to generate a unique (unseen) integer in a limited range.
First, once all of the values in the range have been exhausted there will be no possibilities left, so you'll be left in an endless loop on the next invocation.
Second, it's wasteful of the processor because you are generating useless values on each invocation.
Instead, generate all of the values in range in advance (once), then shuffle them and get the last one from the array on each invocation (and throw an error when none remain):
/**
* Durstenfeld shuffle
*
* - https://stackoverflow.com/a/12646864/438273
* - https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
*/
function shuffleArray (array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
/** Get shuffled array of all integers in range */
function generateShuffledIntegerArray (min, max) {
const arr = [];
for (let i = min; i <= max; i += 1) arr.push(i);
shuffleArray(arr);
return arr;
}
const getUniqueInt = (() => {
const numbers = generateShuffledIntegerArray(1, 75);
return () => {
const n = numbers.pop();
if (typeof n === 'number') return n;
throw new Error('No unique numbers remaining');
};
})();
// Will log 75 integers, then throw on the 76th invocation:
for (let i = 1; i <= 76; i += 1) {
const n = getUniqueInt();
console.log(`${i}:`, n);
}
Code in TypeScript Playground

Your while loop is unnecessary. You could use an "if" statement instead.
To avoid clicking again on your button, you can do a recursive function like:
const chooseNumber = () => {
var r = Math.floor(Math.random() * 75) + 1;
console.log(r)
if(selectedNumbers.indexOf(r) === -1) {
selectedNumbers.push(r);
console.log(selectedNumbers);
} else {
chooseNumber();
}
};

Related

generate 2 different random numbers from an Array?

my only issue so far is when the ships have the same value, I get an error message if I'm using VSC.
TypeError: Assignment to constant variable.
I was trying to get to different values by using the condition but I think it doesn't work.
let grid = [[]];
const letters = "abc".toUpperCase();
// create the Grid
const createGrid = (size) => {
let row;
let col = 0;
for (row = 0; row < size; row++) {
grid[row] = [];
for (col = 0; col < size; col++) {
grid[row][col] = `${letters[row]}${col + 1}`;
}
}
};
createGrid(letters.length);
console.table(grid);
// Start the game
//create ships
const flatArray = grid.reduce((acc, curr) => {
return [...acc, ...curr];
}, []);
function getRandomNumber(len) {
return Math.floor(Math.random() * len);
}
const randomNumber1 = getRandomNumber(flatArray.length);
const randomNumber2 = getRandomNumber(flatArray.length);
while(randomNumber1 == randomNumber2) {
getRandomNumber();
}
var shipOne = flatArray[randomNumber1];
var shipTwo = flatArray[randomNumber2];
console.log(shipOne);
console.log(shipTwo);
Fix an infinite loop
I created a snippet from your example code and it runs forever in the error case you are describing.
A problem is that you have a while loop that will run forever:
while(randomNumber1 == randomNumber2) {
getRandomNumber();
}
You run this code as long as randomNumber1 and randomNumber2 are the same but you update neither of them in the loop so it can never be false.
Try this:
while(randomNumber1 == randomNumber2) {
randomNumber2 = getRandomNumber(flatArray.length);
}
You might also make your code a little smarter and remove elements from the flatArray array you have already chosen.
One other approach you could try is to create a function pickRandomEntries() that will pick N random entries from an array, without ever picking the same ones.
To do this, we shuffle a copy of your flatArray(), then pick the first two items.
This way we never have to check for the ships having the same value:
let grid = [[]];
const letters = "abc".toUpperCase();
const createGrid = (size) => {
let row;
let col = 0;
for (row = 0; row < size; row++) {
grid[row] = [];
for (col = 0; col < size; col++) {
grid[row][col] = `${letters[row]}${col + 1}`;
}
}
};
createGrid(letters.length);
const flatArray = grid.reduce((acc, curr) => {
return [...acc, ...curr];
}, []);
// Shuffle an array into a random order (using Fisher-Yates)
function shuffle(arr) {
for(let i = arr.length - 1; i > 0; i--) {
let index = Math.floor(Math.random() * (i + 1));
[arr[index], arr[i]] = [arr[i], arr[index]];
}
return arr;
}
// Pick count random items from the array
function pickRandomEntries(arr, count) {
let shuffled = shuffle([...arr]);
return shuffled.slice(0, count);
}
let [shipOne, shipTwo] = pickRandomEntries(flatArray, 2);
console.log( { shipOne, shipTwo });
Inside of your while loop if the two random numbers were the same you would be stuck inside an infinite loop. Like Peter stated.
To fix this use the code Peter stated but don't forget you still need to pass in the array length into this function. Otherwise you will have an error:
while(randomNumber1 == randomNumber2) {
randomNumber2 = getRandomNumber(flatArray.length);
}
Thanks!!

Multiplying N positive odd numbers

I'm trying to get the product of N positive odd numbers
function multOdd(n) {
var mult = 1;
var counter=[];
for (var i = 1; i <= 2*n-1; i += 2){
counter.push(i);
}
console.log(counter);
return mult=mult*counter[i];
}
console.log(multOdd(10));
I pushed the numbers into an array and attempted to get the product from them but I can't get it to work.
When you return mult=mult*counter[i] you're only returning the multipication once. It should return mult = 1 * counter[lastElement+2] which will be wrong. In your case, the last element of counter is 19, before exiting for loop i value is i= 19 + 2 = 21. You're returning mult = 1 * 21 = 21.
You can instead return the multipication value by for loop with no need for an array:
function multOdd(n) {
var mult = 1;
for (var i = 1; i <= 2*n-1; i += 2){
mult = mult * i;
}
return mult;
}
If you just want the result for n, use:
function multOdd(n) {
var result = 1;
for (var i = 1; i <= 2*n-1; i += 2){
result = result * i;
}
console.log(result);
return result;
}
console.log(multOdd(4));
If you want an array that has an array indexed by the number of odd numbers up to n you could use:
function multOdd(n) {
let result = 1;
let results = [];
for (let i = 1; i <= 2*n-1; i += 2){
result = result * i;
results[(i+1) / 2] = result;
}
console.log(results);
return results;
}
console.log(multOdd(10));
There are a few ways to get the product of an array of numbers. Here are two easy ones:
Relevant MDN
// Using `Array.prototype.reduce`
[3, 5, 7, 9].reduce((acc, val) => acc * val)
// Using a `for ... of` loop
let product = 1
for (const val of [3, 5, 7, 9]) {
product *= val
}
You could separate out the two steps of your current code into two functions:
const getFirstNOddNums = (n) => {
let oddNums = []
for (let i = 1; i <= 2*n-1; i+=2) {
oddNums.push(i)
}
return oddNums
}
const productOfArray = (arr) => {
return arr.reduce((a, b) => a * b)
}
const N = 5
const firstNOddNums = getFirstNOddNums(N)
console.log(`The first ${N} odd numbers are: ${JSON.stringify(firstNOddNums)}`)
console.log(`The product of the first ${N} odd numbers is: ${productOfArray(firstNOddNums)}`)
let multOdd = (n) => {
let total = 1;
for (let i = 1; i<= 2*n; i+=2){
total *= i;
}
return total;
}
console.log(multOdd(10));
Instead of recursion, We should use the standard mathematical formula for the product of first n positive odd integers which is
Can also be written as (in the form of pi notation)
For this latex image, I used https://codecogs.com/latex/eqneditor.php.
Factorial is
n! = n(n-1)(n-2)(n-3) ... and so on
So we can use Array(n).fill() to get an array of 10 elements and reduce them to get a factorial by
Array(n).fill().reduce((v,_,i) => (i+1) * v || 2)
Then we divide it by 2 to the power n times the n!. Which is what we want. The advantage here is that, this makes your solution, a one liner
let n = 10
let answer = Array(2*n).fill().reduce((v,_,i) => (i+1) * v || 2) / (Math.pow(2,n) * Array(n).fill().reduce((v,_,i) => (i+1) * v || 2))
console.log(answer)

Best approach to random 10 numbers between 1 and 100 no dupes in javascript? [duplicate]

This question already has answers here:
Generate unique random numbers between 1 and 100
(32 answers)
Closed 4 years ago.
This has been asked dozens of times, but somehow, after reading many answers, I'm not convinced. I'm not cleared about the best way to do it, performance and code simplicity.
Should I set the list [1.. 100] and keep picking random (it will run 10 times) from there to another array, avoiding searching for it every new random?
Should I develop and run 10 times (at least) a random function to return a 1.. 100, checking if it is not a dupe and put it into an array?
Some Javascript function that I'm missing?
Thanks
You can use a while loop to generate random numbers with Math.random() and add the numbers to a Set which contains only unique values.
var randoms = new Set();
while(randoms.size<10){
randoms.add(1 + Math.floor(Math.random() * 100));
}
console.log([...randoms.values()]);
You can also just use an Array and check if the generated random number already exists in it before pushing it to the Array.
var randoms = [];
while(randoms.length<10){
var random = Math.ceil(1 + Math.floor(Math.random() * 100));
if(randoms.indexOf(random)==-1){
randoms.push(random);
}
}
console.log(randoms);
For a more generic function, you can use this:
function generateRandoms(min, max, numOfRandoms, unique){
/*min is the smallest possible generated number*/
/*max is the largest possible generated number*/
/*numOfRandoms is the number of random numbers to generate*/
/*unique is a boolean specifying whether the generated random numbers need to be unique*/
var getRandom = function(x, y){
return Math.floor(Math.random() * (x - y + 1) + y);
}
var randoms = [];
while(randoms.length<numOfRandoms){
var random = getRandom(min, max);
if(randoms.indexOf(random)==-1||!unique){
randoms.push(random);
}
}
return randoms;
}
function generateRandoms(min, max, numOfRandoms, unique){
var getRandom = function(x, y){
return Math.floor(Math.random() * (x - y + 1) + y);
}
var randoms = [];
while(randoms.length<numOfRandoms){
var random = getRandom(min, max);
if(randoms.indexOf(random)==-1||!unique){
randoms.push(random);
}
}
return randoms;
}
console.log(generateRandoms(1, 100, 10, true));
This technique creates N1 numbers (the total range) and shuffles them, then picks the top N2 number (how many we actually want), we'll use Fisher-Yates shuffle.
const n1 = 100;
const n2 = 10;
let pool = [...Array(n1).keys()];
var result = [];
while (result.length < n2) {
let index = Math.floor(Math.random() * pool.length);
result = result.concat(pool.splice(index, 1));
}
console.log(result);
var randomArray = [];
while(randomArray.length < 10) {
var random = Math.round(Math.random() * 100);
if(randomArray.indexOf(random) === -1) {
randomArray.push(random);
}
}
console.log(randomArray);
#2 would be the most efficient.
var nums = []
while(nums.length < 10) {
var n = Math.round(Math.random()*100);
if (!nums.includes(n)) nums.push(n);
}
console.log(nums);
You could also use Set in a newer browser, which would be a little faster than manually checking for existence:
var nums = new Set();
while(nums.size < 10) {
var n = Math.round(Math.random()*100);
nums.add(n);
}
console.log([...nums.values()]);
This function adds all numbers from betweenStart to betweenEnd, randomizes them over randomRuns loops and returns a list with amount entries:
function randomNumbersBetweenXAndY(betweenStart, betweenEnd, amount, randomRuns) {
if (betweenStart === void 0) { betweenStart = 0; }
if (betweenEnd === void 0) { betweenEnd = 100; }
if (amount === void 0) { amount = 10; }
if (randomRuns === void 0) { randomRuns = 1; }
//Verify parameters
var maxPossibleCandidates = Math.abs(betweenStart - betweenEnd) + 1;
if (amount > maxPossibleCandidates) {
console.warn("You cannot get more unique numbers between " + betweenStart + " and " + betweenStart + " than " + maxPossibleCandidates + ". " + amount + " is too many!");
amount = maxPossibleCandidates;
}
//array to return
var list = [];
//fill array
for (var index = betweenStart; index <= betweenEnd; index++) {
list.push(index);
}
//Randomize
while (randomRuns--) {
for (var index = 0; index < list.length; index++) {
var randomIndex = Math.floor(Math.random() * list.length);
var tmp = list[index];
list[index] = list[randomIndex];
list[randomIndex] = tmp;
}
}
//Return data
return list.slice(0, amount);
}
//TEST
console.log(randomNumbersBetweenXAndY(1, 100, 10));

I need to make an array of 15 random integers. I have a function but dont want numbers to repeat

I'm working on a project for school. I need to generate an array of 15 random integers between 1 & 50. I have a function, but I would not like for the numbers to repeat. (for example, if the number 3 is located at index 0, I would not like for it to show up again in the array.) If I could get some help on not getting repeat numbers, that would be great.
Thank you for any help!
var arr;
function genArray() {
//generates random array
arr = [];
for (var i = 0; i < 15; i++) {
var min = 1;
var max = 50;
var arrayValue = Math.floor(Math.random() * (max - min + 1)) + min;
arr.push(arrayValue);
}
arr.sort(function(a, b) {
return a - b
});
console.log(arr);
}
In the loop generate a new random number while the number is in the array. In other words only continue when the new number is not in the array already.
var arr;
function genArray() {
//generates random array
arr = [];
for (var i = 0; i < 15; i++) {
var min = 1;
var max = 50;
do
{
var arrayValue = Math.floor(Math.random() * (max - min + 1)) + min;
}while(arr.includes(arrayValue))
arr.push(arrayValue);
}
arr.sort(function(a, b) {
return a - b
});
console.log(arr);
}
genArray();
You can make a function in which check the number if its already in array than regenrate the number else push the number in array
var arr;
function genArray() {
//generates random array
arr = [];
for (var i = 0; i < 15; i++) {
var min = 1;
var max = 50;
var arrayValue = Math.floor(Math.random() * max) + min;
if(checkno(arrayValue)==true)
arr.push(arrayValue);
}
arr.sort(function(a, b) {
return a - b
});
console.log(arr);
}
function checkno(var no)
{
for(var i=0;i<arr.length;i++)
{
if(arr[i]==no)
return false;
else
return true;
}
}
An alternate solution involves the Set object, sets only have unique elements, multiple elements of the same value are ignored.
Example of the set object implemented for this use:
var temp = new Set();
while (temp.size < 15) {
var min = 1;
var max = 50;
temp.add(Math.floor(Math.random()*(max-min+1))+min);
}
This approach uses Arrow functions, forEach and includes functions.
let LENGTH = 15;
let numbers = new Array(LENGTH).fill();
let findRandomNumber = (i) => {
let rn;
while (numbers.includes((rn = Math.floor(Math.random() * 50) + 1))) {}
numbers[i] = rn;
};
numbers.forEach((_, i) => findRandomNumber(i));
console.log(numbers.sort((a, b) => a - b));
.as-console-wrapper {
max-height: 100% !important
}
You do not need to check the resulting array and regenerate the number. It is not efficient.
Please take a look at the following snippet:
function get_N_rand(N = 15, min = 1, max = 50) { // set default values
var N_rand = [], range = [];
for (var i = min; i <= max;) range.push(i++); // make array [min..max]
while (N_rand.length < N) { // cut element from [min..max] and put it into result
var rand_idx = ~~(Math.random() * range.length);
N_rand.push(range.splice(rand_idx, 1)[0]);
}
return N_rand;
}
console.log(JSON.stringify( get_N_rand() )); // run with defaults
console.log(JSON.stringify( get_N_rand(6, 10, 80) )); // run with arbitraries

Generating random number in Array without repeatition - JavaScript

so I know this questing has been asked, but all the answers that were given are already known to me. I don't want to make a variable of all the posible numbers (that was always the answer). So to go to the question, I want to make a random number generator, that will generate me 7 numbers, that must not be the same. For example, I get random numbers:
"5,16,12,5,21,37,2" ... But I don't want the number 5 to be used again, so I want different numbers. I made a code for the generation, but I can not think of any good method/way to do this. I was thinking that maybe check if the number is already in array and if it is, then generate another number, but as I'm amateur in JavaScript, I don't know how to do this. So here is my JavaScript code:
// JavaScript Document
function TableOn()
{
document.write("<table border='1'>");
}
function TableOff()
{
document.write("</table>");
}
function RandNum()
{
var n = new Array();
for(var i=0;i<7;i++)
{
n[i] = Math.round((1+(Math.random()*40)));
}
TableOn();
for(var c=0;c<7;c=c+1)
{
document.write("<tr><td>"+n[c]+"</td></tr>");
}
TableOff();
}
In HTML I just have a button, that is onclick="RandNum()" ... Pardon for my English.
I would do it like this:
var nums = [], numsLen = 5, maxNum = 100, num;
while (nums.length < numsLen) {
num = Math.round(Math.random() * maxNum);
if (nums.indexOf(num) === -1) {
nums.push(num);
}
}
This generates an array with 5 random numbers in the range 0..100.
(numsLen cannot be greater than maxNum.)
These commands can be used to check if a value is/is not in your array:
if ( !!~n.indexOf(someVal) ) {
// someVal is in array "n"
}
if ( !~n.indexOf(someVal) ) {
// someVal is not in array "n"
}
I'd use a string, storing the generated random numbers with a divider. Then check if the newly generated number is in that string.
Something like this
generated = "";
for(var i=0;i<7;i++)
{
generate = Math.round((1+(Math.random()*40))); //generate = 5
while (generated.indexOf("[" + generate + "]") != -1) { //checking if the [5] is already in the generated string, and loop until it's a different number
generate = Math.round((1+(Math.random()*40))); //get a new random number
}
generated += "[" + generate + "]";
n[i] = generate;
}
or you can take another longer approach
for(var i=0;i<7;i++)
{
repeated = true;
while (repeated) {
repeated = false;
generate = Math.round((1+(Math.random()*40)));
for (var a=0; a < i, a++) {
if (generate == n[a]) { repeated = true; }
}
}
n[i] = generate;
}
Here's a function to generate an array of n unrepeated random numbers in [min, max):
function rands(n, min, max) {
var range = max - min;
if (range < n)
throw new RangeError("Specified number range smaller than count requested");
function shuffle() {
var deck = [], p, t;
for (var i = 0; i < range; ++i)
deck[i] = i + min;
for (i = range - 1; i > 0; --i) {
p = Math.floor(Math.random() * i);
t = deck[i];
deck[i] = deck[p];
deck[p] = t;
}
return deck.slice(0, n);
}
function find() {
var used = {}, rv = [], r;
while (rv.length < n) {
r = Math.floor(Math.random() * range + min);
if (!used[r]) {
used[r] = true;
rv.push(r);
}
}
return rv;
}
return range < 3 * n ? shuffle() : find();
}
This code checks the range of possible values and compares it to the number of random values requested. If the range is less than three times the number of values requested, the code uses the shuffle to avoid the terrible performance of the lookup approach. If the range is large, however, the lookup approach is used instead.
Not sure if OP's requirement of non-repeating is really needed, but here's a fiddle of something that could work if your number range isn't too big:
http://jsfiddle.net/6rEDV/1/
function range(start, end, step) {
if (typeof step === 'undefined') {
step = 1;
}
if (typeof start === 'undefined' || typeof end === 'undefined') {
throw TypeError('Must have start and end');
}
var ret = [];
for (var i = start; i <= end; i += step) {
ret.push(i);
}
return ret;
};
// source: http://stackoverflow.com/a/6274381/520857
function shuffle(o) { //v1.0
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
function getNonRepeatingRand(min, max, num) {
var arr = shuffle(range(min, max));
return arr.slice(0, num-1);
}
// Get 7 random numbers between and including 1 and 1000 that will *not* repeat
console.log(getNonRepeatingRand(1,1000,7));
A possibly slower, but less memory intensive method:
http://jsfiddle.net/Qnd8Q/
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getNonRepeatingRand(min, max, num) {
var ret = [];
for (var i = 0; i < num; i++) {
var n = rand(min, max);
if (ret.indexOf(n) == -1) {
ret.push(n);
} else {
i--;
}
}
return ret;
}
console.log(getNonRepeatingRand(1,5,5));
var n = new Array(),num;
function TableOn()
{
document.write("<table border='1'>");
}
function TableOff()
{
document.write("</table>");
}
function check_repition()
{
num=Math.round((1+(Math.random()*40)))
if(n.indexOf(num)==-1)
return true;
else
return false;
}
function RandNum()
{
for(var i=0;i<7;i++)
{
if(check_repition())
n[i] =num;
else // keep checking
{
check_repition()
n[i] =num;
}
}
TableOn();
for(var c=0;c<7;c=c+1)
{
document.write("<tr><td>"+n[c]+"</td></tr>");
}
TableOff();
}
RandNum()

Categories