Counting duplicate random numbers from a for loop - javascript

I am trying to create a score predictor based on a teams goal difference (football). I am new to JavaScript, and I have managed to get this far.
I want it to be like spinning a ten-sided dice 20 times + the team's goal difference. I have got this bit sorted I think. With my code now I have a list of random numbers logged in the console which is what I wanted. Now I would like to choose a number (e.g., 2) and see how many times this occurs in the list. I'd like to save this in a new variable called homeFinalScore (So if '2' occurs three times in the list of random numbers, the homeFinalScore variable should be 3). I've tried several things but have been unable to sort it yet!
Any help would be extremely helpful. Thank you in advance!
var homeFinalScore = 0;
function calculateScore(){
var homeTeam = document.getElementById("HomeTeam").value;
var awayTeam = document.getElementById("AwayTeam").value;
var homeGd = parseInt(document.getElementById("HomeGD").value);
var awayGd = parseInt(document.getElementById("AwayGD").value);
var homeGd = 20 + homeGd;
var awayGd = 15 + awayGd;
for (i = 0; i < homeGd; i++) {
var randNum = Math.floor(Math.random() * 11);
console.log(randNum);
}
}

You can create an array, use Array.prototype.push() to push randNum to the array, then use Array.prototype.filter(), .length to determine how many occurrences of a value are present within array.
var homeGd = 20 + 2;
var awayGd = 15 + 2;
var arr = [];
function countOccurrences(n, arr) {
return arr.filter(function(value) {
return value === n
}).length;
}
for (i = 0; i < homeGd; i++) {
var randNum = Math.floor(Math.random() * 11);
arr.push(randNum);
}
console.log(arr);
console.log(countOccurrences(2, arr));
Alternatively, you can increment a variable when randNum is equal to a value.
var homeGd = 20 + 2;
var awayGd = 15 + 2;
var n = 0;
var num = 2;
for (i = 0; i < homeGd; i++) {
var randNum = Math.floor(Math.random() * 11);
console.log(randNum);
if (randNum === num) {
++n
}
}
console.log("occurrences of 2:", n);

const homeGd = 10;
const randomNumbers = []; // array of random numbers
for (i = 0; i < homeGd; i++) {
randomNumbers.push(Math.floor(Math.random() * 11));
}
const countBy = randomNumbers.reduce((acc, current) => {
acc[current] = (acc[current] || 0) + 1;
return acc;
}, {});
console.log(countBy);

Related

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));

Alternate between subtracting and adding array items

I'm trying to create a formula for calculating PI using the Gregory-Leibniz series. I've created a for loop that's populating a new array with the individual values, but I need a way to then alternate between subtracting and adding each array item and then spit out the resulting number. Essentially, I need to get to something like this:
(4/1) - (4/3) + (4/5) - (4/7) + (4/9) - (4/11) + (4/13) - (4/15)
The following for loop is populating the new array correctly:
var arrLimit = 39;
var newArray = [];
for(i = 1; i <= arrLimit; i += 2) {
newArray.push(4/i);
}
At this point I get stuck. I need some way to take newArray and alternate between subtracting and adding the values, and then produce the final number.
You can sum your array with reduce, then judge *=-1 or *=1 based on the index of the array.
The code will be like below:
//Test Case 1
var arrLimit = 39;
var newArray = [];
for(i = 1; i <= arrLimit; i += 2) {
newArray.push(4/i);
}
console.log(newArray.reduce(function(pre, cur, currentIndex){
return pre+cur*(currentIndex%2 ? -1 : 1);
}, 0));
//Test Case 2
arrLimit = 11139;
newArray = [];
for(i = 1; i <= arrLimit; i += 2) {
newArray.push(4/i);
}
console.log(newArray.reduce(function(pre, cur, currentIndex){
return pre+cur*(currentIndex%2 ? -1 : 1);
}, 0));
Keep an extra variable, isNeg = true. On each iteration of the loop, just alternate it with isNeg = !isNeg;.
var arrLimit = 39;
var newArray = [];
var isNeg = false;
for(i = 1; i <= arrLimit; i += 2) {
isNeg = !isNeg;
var val = 4/i;
if (isNeg) {
val *= -1;
}
newArray.push(val);
}
You can also assign 1 to the variable, and multiple it by -1 each time to do the flip:
var arrLimit = 39;
var newArray = [];
var factor = 1;
for(i = 1; i <= arrLimit; i += 2) {
factor *= -1;
var val = factor * 4 / i;
newArray.push(val);
}
Personally I favor the second approach, but both work just fine.
I need some way to take newArray and alternate between subtracting and adding the values, and then produce the final number.
You can do that with Array.prototype.reduce
// Your code, unchanged
var arrLimit = 39;
var newArray = [];
for(i = 1; i <= arrLimit; i += 2) {
newArray.push(4/i);
}
// reduce the array to the final result
// (2*(-i%2)+1) alternates between `-1` and `1`.
var result = newArray.reduce( (prev,curr,i) => prev + (2*(-i%2)+1)*curr );
console.log( result );
How about doing away with the array in the first place and being able to "calculate" pi with as many terms as you like.
let pi = 0,
terms = 100;
for (var i = 0; i < terms; i++){
pi += 4/(2*i + 1) * ( i % 2 == 0 ? 1 : -1)
}
console.log(pi);
You could add an extra variable. If you want you could sum at the same time.
var arrLimit = 39;
var newArray = [];
var a=-1
var sum =0
for(i = 1; i <= arrLimit; i += 2) {
a*=-1;
newArray.push(a*4/i);
sum+=a*4/i
}
You can look at the length of newArray when you build it and multiply the value by -1 or +1
var arrLimit = 39;
var newArray = [];
for(i = 1; i <= arrLimit; i += 2) {
newArray.push(4 / i * (newArray.length % 2 ? 1 : -1));
}
console.log(newArray);

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

JS: get x amount of random numbers inside interval with while loop

I'm working on a card game with six available suits, but there can be 2-6 players and I only want the number of suits to match the amount of players.
let players = 4
const suits = [1, 2, 3, 4, 5, 6]
Of course, I want them to come out randomly.
I have come up with the following solution:
export function getRandomSuits(nrOfPlayers) {
const rangeMin = 1;
const rangeMax = 6;
const amount = nrOfPlayers;
let nums = [];
let getRandomNumber = function() {
return Math.floor((Math.random() * rangeMax) + rangeMin);
}
while (nums.length < amount) {
let nr = getRandomNumber();
var numberExists = _.indexOf(nums, nr);
console.log(numberExists);
if(numberExists < 0) {
nums.push(nr);
}
}
return nums;
}
It's been a while since I used the "while loop" thingy, so I'm not feeling very comfortable with it.
My questions are:
Is this good practice or is there a better solution?
Are there any performance or other practical reasons why this solution is bad?
Am I overthinking it?
In my opinion, I see no need of the function getRandomNumber(). Nonetheless, this is up to preference.
I would go with:
export function getRandomSuits(nrOfPlayers) {
const rangeMin = 1;
const rangeMax = 6;
let nums = [];
while (nums.length < nrOfPlayers) {
let nr = Math.floor((Math.random() * rangeMax) + rangeMin);
var numberExists = _.indexOf(nums, nr);
if(numberExists < 0) {
nums.push(nr);
}
}
return nums;
}
Not necessarily. Merely a matter of cleanliness and preference.
Maybe? :-)
Second method (Slightly better) with a temporary array:
export function getRandomSuits(nrOfPlayers) {
const rangeMin = 1;
const rangeMax = 6;
var tempNum = [];
for(i = 0; i <= rangeMax - rangeMin; i++){
tempNum[i] = rangeMin + i;
}
let nums = [];
while (nums.length < nrOfPlayers) {
let index = Math.floor(Math.random() * tempNum.length);
var numberExists = _.indexOf(nums, tempNum[index]);
if(numberExists < 0) {
nums.push(tempNum[index]);
tempNum.splice(tempNum, index));
}
}
return nums;
}

JS: Array shuffling, not string shuffling

I am trying to shuffle a string array using JS. I hard-coded three sets of characters. 3 characters from each set were chosen at random and then concatenated. So the concatenated string is 3 letters, followed by 3 numbers, followed by 3 symbols. I want to shuffle this concatenated string so their order is randomized.
I already checked How to randomize (shuffle) a JavaScript array?, and my algorithm and code essentially matches what the second solution was, except for the fact that I have the shuffle loop in a bigger function (instead of as its own function). Perhaps I should add the shuffling to its own function and call it within the bigger function, but I think that will still give me the same result.
The "shuffling part" of the function isn't actually shuffling. When I debug it with console.log(temp) and console.log(tp[rnd]), the correct values are showing. Basically, the function is returning the unshuffled string that I wanted to shuffle.
var letterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var numberSet = "0123456789";
var symbolSet = "~!##$%^&*()-_+=><";
this.generatePassword = function() {
var rl = "";
var rn = "";
var rs = "";
var tp = "";
// 3 random letters
for(var i = 0; i < 3; i++) {
var rnd = Math.floor((Math.random() * 52));
rl += letterSet[rnd];
}
// 3 random numbers
for(var i = 0; i < 3; i++) {
var rnd = Math.floor((Math.random() * 10));
rn += numberSet[rnd];
}
// 3 random symbols
for(var i = 0; i < 3; i++) {
var rnd = Math.floor((Math.random() * 17));
rs += symbolSet[rnd];
}
// String concatenation
tp = rl + rn + rs;
// Shuffling part
for(var i = 0; i < tp.length; i++) {
var rnd = Math.floor(Math.random() * tp.length);
var temp = tp[i];
tp[i] = tp[rnd];
tp[rnd] = temp;
}
return tp;
}();
I don't understand what is going wrong.
Your shuffle is a bit off, I looked at this which uses an array to shuffle.
// String concatenation
tp = rl + rn + rs;
tp=tp.split('');
// Shuffling part
for(var i = 0; i < tp.length; i++) {
var rnd = Math.floor(Math.random() * tp.length);
var temp = tp[i];
tp[i] = tp[rnd];
tp[rnd] = temp;
}
tp=tp.join("");
When you perform the assignments tp[i] = tp[rnd] and tp[rnd] = temp it is not changing the value of tp because strings are immutable. It is possible to manipulate a string and replace values using methods on String. Change those two assignments to the following:
for (var i = 0; i < tp.length; i++) {
var rnd = Math.floor(Math.random() * tp.length);
var temp = tp[i];
tp = tp.replace(tp.substr(i, 1), tp[rnd]);
tp = tp.replace(tp.substr(rnd, 1), temp);
}

Categories