Generate 7 unique random numbers in javascript - javascript

I have a project i'm working on.
I am to basically recreate lotto on the client side using javascript to generate 6 random numbers plus a bonus ball. as we all know, lotto numbers cannot be the same. this is where my question comes in.
Is it possible to remove a number that has been generated from being available in the next time round in the loop? This would make the function completely random. or do I need to still compare the number with the others in the array using indexOf?
for example, is the following possible?,
the first number that generates is 25,
the function then removes that number from being able to come up again.
so on...
Here is my js code,
function play(){
numbersArray = [];
for (i=0; i<=6;){
n = Math.floor(Math.random()*40)+1;
a = numbersArray.indexOf(n);
if ( a == "-1"){
numbersArray[i] = n;
i++;
var ballId = "ball"+i;
if( i != "7"){
document.getElementById(ballId).innerHTML = '<p>'+ n +'</p>';
} else {
document.getElementById("bonus").innerHTML = '<p>'+ n +'</p>';
}
} //end of if
}//end of for loop
}//end of play function

You need to create an object, in this case you could use an array, that holds all the possible numbers that can appear on the ball, we'll cal it n. Then you can use a while loop to keep picking numbers from that array, and splice/remove that specific number from the array on every iteration.
function play(n) {
var picks = [];
// Store possibilities in the numbersArr array
var numbersArr = [];
// n is the max number you can choose to appear on a ball
for ( var i = 0; i < n; i++ ) {
numbersArr.push(i);
}
while (picks.length < 7){
var randomIndex = Math.floor(Math.random() * numbersArr.length);
picks.push(numbersArr[randomIndex]);
numbersArr.splice(randomIndex, 1);
}
return picks;
}

Related

How to iterate over an array of numbers to find the first number that occurs 3 times in the array

I have the following code
let range = [1,2,3];
let multiples = [1,2,3,4,5,6,2,4,6,3,6];
I want to find the first number in the multiples array that occurs range.lenght times (3);
I want to start with multiples[0] check how many times it occurs in multiples, if it occurs 3 times I want to return multiples[0], if it is less than 3 times, I want to check how many times multiples[1] occurs in the multiples array. If multiples[1] occurs 3 times I want to return multiples[1], else I move on to check multiples[2], etc. until I find a number that occurs 3 times. In the code above I should return 6.
I've looked at
How to count the number of certain element in an array?
and
Idiomatically find the number of occurrences a given value has in an array
and
get closest number out of array
among other research but have not figured it out yet.
I tried to simplify the question as much as possible. But if more info is needed it relates to this challenge on freeCodeCamp. Where I am at with my code is
function smallestCommons(arr) {
let sortArr = arr.sort((a, b) => a - b);
console.log(sortArr);
let range = [];
for (let i = sortArr[0]; i <= sortArr[1]; i++) {
range.push(i);
}
console.log("range = " + range);
let maxNum = range.reduce( (a, b) => a * b);
console.log("maxNum = " + maxNum);
let multiples = [];
for (let i = 0; i < maxNum; i++) {
let j = 0;
do {
multiples.push(j + range[i]);
j += range[i];
} while (j < maxNum);
//j = 0;
}
for (let i = 0; i < multiples.length; i++) {
let numberToFind = multiples[i];
/*stuck here hence my question, maybe I shouldn't even start with a for loop*/
//tried reduce, forEach, filter, while loop, do while loop
}
console.log("multiples = " + multiples);
}
console.log(smallestCommons([1,3]));
The logs are
1,3
range = 1,2,3
maxNum = 6
multiples = 1,2,3,4,5,6,2,4,6,3,6,NaN,NaN,NaN
What you can do is, first split your string with , and then using below function loop for check.
function countLength(arr, checkNumber) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === checkNumber) {
count++;
}
}
return count;
}
countLength(list, NUMBER YOU WANT TO CHECK);
And if you want to check first number occur for 3 time then you need to make change in function and introduce .map or .filter in action to count number.
Example
const multiples = [1,2,3,4,5,6,2,4,6,3,6];
let occurance_arr=[];
const aCount = [...new Set(multiples)].map(x => {
if(multiples.filter(y=> y==x).length == 3) {
occurance_arr.push(x);
}
});
console.log(occurance_arr);
Above code will give you 6 in console, if you have multiple value then 0th element is the answer you are looking for which is first three time occurrence of item.
You can loop through your list keeping an object that maps each number to the number of times you've seen it. You can check the counts object as you loop, so if you see a number and the count is one less than your target, you can return it. If you make it through the loop without returning you didn't find what you're looking for — return something sensible :
let range = [1,2,3]
let multiples = [1,2,3,4,5,6,2,4,6,3,6]
function findFirstMult(arr, len){
let counts = {} // to keep track of how many times you've seen something
for (let n of arr){ // loop throught the array
if (!counts[n]) counts[n] = 0 // if it's then first time you've seen n, defined that key
if (counts[n] == len - 1) return n // found it
counts[n] +=1 // otherwise increase the count
}
return undefined
}
console.log(findFirstMult(multiples, range.length))
This will require only one loop through the array in the worse case and will return early if if finds something.

JavaScript to check which one of the given numbers differs from other

I am stuck on a problem. I want to print the index of an array which differs from other elements of that array in evenness. To be more specific the input would be like 5 even numbers and 1 odd number. So print the position(index+1) of odd number.
My code
function Test(numbers){
var e = 0; //number of even numbers
var o = 0; //number of odd numbers
console.log(numbers.length);
for(var i = 0; i < numbers.length; i++){
if(numbers[i] % 2 == 0){
e++;
var pose = i; //index of even no
}
else{
o++
var poso = i; //index of odd number
}
}
if(e==1){ //only one even number
console.log(pose+1);
}
else if(o==1){ //only one odd number
console.log(poso+1);
}
else{
console.log("no number differs");
}
}
Test("2 4 7 8 6");
Expected output = '3';
The console prints :
"no number differs".
I have debugged and I found the problem. The console.log(numbers.length); is printing 9. That is it is including blank spaces as well. Same if we put comma ',' in between the numbers. Also if there is a two digit number it treats them as 2 separate elements.
Now I know that i can add code at the beginning to check if i=1,3,5... to break the loop but I would like to know if there is a better solution. Also if the solution is passing array in different format I would like to know how can we correct the code if we want to pass as above.
Pass an array as an argument like below.
function Test(numbers){
var e = 0; //number of even numbers
var o = 0; //number of odd numbers
console.log(numbers.length);
for(var i = 0; i < numbers.length; i++){
if(numbers[i] % 2 == 0){
e++;
var pose = i; //index of even no
}
else{
o++
var poso = i; //index of odd number
}
}
if(e==1){ //only one even number
console.log(pose+1);
}
else if(o==1){ //only one odd number
console.log(poso+1);
}
else{
console.log("no number differs");
}
}
var x = [2,4,7,8,6];
Test(x);
Your Program is absolutely fine.
I guess the problem is with how you are passing data to your function Test.
You are passing a string instead of array.
it should be like:
Test([2,4,7,8,6]);
Also If you want to pass it as string just make sure you split the String with ',' comma and make an array of the numbers and then feed it to your for loop.
In your code you are passing the argument as a string, but I guess you may need to pass an array.
If it is so then you can look into array#forEach method
Hope this snippet will be useful
function Test(numbers) {
// looping through the array
numbers.forEach(function(item, index) {
//checking if it is odd or even
if (item % 2 == 0) {
console.log("current number is Even & its index is " + index);
} else {
//updating index
var modIndex = index+1;
console.log("current number is Odd & its modified index is " + modIndex);
}
})
}
var num = ['2','4','7','8','6']
Test(num);
DEMO

How do I grab the two largest integers from a Javascript Array and return the value to the DOM?

I've written a solution to take a list of integers entered through a form. It works. It gives you the sum of the two largest integers and posts it in the DOM.
However, it's not very efficient for large arrays of say 1 million integers.
How can I improve this solution to be more efficient.
App.js
// This function reverses the order of the array and places the biggest numbers first
function sortNumber(a, b) {
return b - a;
}
// this function is used to ensure the user didn't enter any letters
function getArray() {
var alphaExp = /^[a-zA-Z]+$/;
// This function takes the array, orders it, adds the sum of the two largest numbers and returns the value
function sumOf(x) {
// Sort the ary with the sortNumber function
array.sort(sortNumber);
// Then we add the two biggest numbers of the array and save it to the result variable.
var result = array[0] + array[1];
// Then we share the result with the user by updating the browser
var myHeading = document.querySelector('h2');
myHeading.textContent = "The sum of your two biggest numbers is: " + result;
// Like a good student, it's important to show your work
var showYourWork = document.querySelector('h3');
showYourWork.textContent = array[0] + " + " + array[1] + " = " + result;
}
// This grabs the value of the input
var arrayField = document.getElementById('arrayField').value;
if (arrayField.match(alphaExp)) {
// Fail if user enters letters
var raiseError = document.querySelector('h5');
raiseError.textContent = 'No not letters! We want numbers!!';
} else {
var array = JSON.parse("[" + arrayField + "]");
if (arrayField.length < 2) {
// If the user enters only 1 number, tell them to enter more!
var raiseError = document.querySelector('h5');
raiseError.textContent = 'Please enter atleast two numbers seperated by commas for us to add!'
} else {
// When the user enters a list of numbers, run the sumOf function.
sumOf(arrayField);
//Make the error go away
var raiseError = document.querySelector('h5');
raiseError.textContent = '';
}
}
};
// use an eventlistener for the event (This is where the magic happens)
var subButton = document.getElementById('subButton');
subButton.addEventListener('click', getArray, false);
You don't have to sort it, just search linearly for the two biggest ones:
EDIT: the code below should work now and is asymptotically faster than the OP's code. The OP does sorting first which can be done in O(n log n), assuming a random list. My code does a linear search through the list in O(cn) with c = 2 (the two loops are not necessary but simple). The solution for ceil(n log n) = 2n with n a positive integer is 14, that is for every list longer than 14 entries the code below is faster. E.g.: for one million entries the relation is 13,815,511 to 2,000,000, more than six times faster. You can do the same thing in a single loop which halves the runtime (theoretically, but it is also a tiny bit faster because of the better locality).
function maxtwo_wrong(a){
var b1 = -Infinity;
var b2 = -Infinity;
for (var i=0; i < a.length; i++) {
if (a[i] > b1) {
b1 = a[i];
}
}
for (var i=0; i < a.length; i++) {
if (a[i] > b2 && a[i] < b1) {
b2 = a[i];
}
}
return [b1,b2];
}
EDIT-2: The code above maxtwo_wrong seems not to fit the requirements, so I wrote another one maxtwo_rightand put it below. Please, OP, tell me which one fulfills your requirements such that I can delete the wrong one.
EDIT-3: made it simpler and correct.
function maxtwo_right(a){
var b1 = -Infinity;
var b2 = -Infinity;
for (var i=0; i < a.length; i++) {
// If the current entry is bigger than variable b1
// keep the old value in the variable b2 and set b1 to the
// value of the current entry
if (a[i] > b1) {
b2 = b1;
b1 = a[i];
}
// if the current entry equals b1 set the variable b2 to
// the value of the current entry
else if(a[i] === b1){
b2 = a[i];
}
}
// return the sum of the two variables as requested
return b1 + b2;
}
I finally found some time to sit down and work this one out.
I was looking at the problem all wrong.
Here is my new solution
// This function adds the sum of the two largest integers of an array and returns the value
function topTwoInt(theArray) {
var intArray = theArray;
var highestInt = -Infinity;
var secondHighestInt = -Infinity;
var answer = 0;
//Loop through the array
for (var i=0; i < intArray.length; i++) {
//grab the biggest int and assign it to the highestInt variable;
if (intArray[i] > highestInt) {
secondHighestInt = highestInt;
highestInt = intArray[i];
}
//If the next number is equal too highestInt or greater than secondHighestInt
//Make that number become the new secondHighestInt
else if(intArray[i] === highestInt || intArray[i] > secondHighestInt) {
secondHighestInt = intArray[i];
}
}
answer = highestInt + secondHighestInt;
return answer;
};
This solution is largely inspired by #deamentiaemundi
Thanks man.

Javascript convert array of numbers with duplicates into unique sets of numbers

I have a javascript sorting algorithm problem which I am struggling to solve efficiently .
I have an array of numbers which I am calling cards e.g. [1,2,3,4,5,6,7,8,9,10]
Each day I have 6 teaching sets. In each set I want to display a maximum of 5 RANDOM & UNIQUE cards. Each card must be displayed exactly 3 times a day.
What I have done so far is to create 6 empty arrays (sets). I then iterate through my cards 3 times each attempting to add them to a random set if the card does not already exist in that array. Sometimes it works, but most of the time I get a problem where I have only one array with space left and that array already contains the card. my code:
Assume in my code that numberOfSetsPerCard = 3 & totalSets = 6. The only library available is JQuery.
shuffleIntoSets : function(cards, numberOfSetsPerCard, totalSets) {
var sets = [];
// initialize the sets as empty arrays
for (i = 0; i < totalSets; i++) {
sets[i] = [];
}
$.each(cards, function(index, card) {
for(x=0;x<numberOfSetsPerCard;) {
// attempt to place the card in a set which doesnt already contain the card
setNo = Math.floor((Math.random() * totalSets));
console.log("setNo: " + setNo);
if(jQuery.inArray(card,sets[setNo]) == -1 && sets[setNo].length<5) {
console.log(setNo + "does not contain: " + card);
sets[setNo].push(card);
console.log("Added the card, set now looks like :" + sets[setNo]);
x++;
}
}
});
return sets;
},
This is my solution to your problem, it is a bit long, but i think it a bit long, but it definitely creates randomness in the teach sets, and satisfy the conditions you have stated
codepen link: http://codepen.io/anon/pen/yyoaZy
html/include jquery:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
js:
//-----------------------------------------------
//For this question on StackOverflow:
//http://stackoverflow.com/questions/28192127/javascript-convert-array-of-numbers-with-duplicates-into-unique-sets-of-numbers
//-----------------------------------------------
var cards = [1,2,3,4,5,6,7,8,9,10];
var numOfTeachingSets = 6;
var numOfUniqueCardsPerTeachingSet = 5;
var numOfCardRepetitionPerDay = 3;
var shuffleCards = function(cards, numOfTeachingSets, numOfUniqueCardsPerTeachingSet, numOfRepetitionPerCard){
if(cards.length*numOfRepetitionPerCard != numOfTeachingSets*numOfUniqueCardsPerTeachingSet){
alert("invalid param");
return null;
}
//since each card is required to repeat numOfRepetitionPerCard times
//the available choices should be numOfRepetitionPerCard times of the original deck of cards
var availableCardChoices = cards.concat([]);
for (var i=0;i<numOfRepetitionPerCard-1;i++){
availableCardChoices = availableCardChoices.concat(cards);
}
//Record down items from [availableCardChoices] has been picked
var choosenList = [];
//Put 6 sets of unique cards into the result
var result = [];
for (var i=0;i<numOfTeachingSets;i++){
result.push( pickOutUniqueNumberSet(availableCardChoices,numOfUniqueCardsPerTeachingSet, choosenList) );
}
//return the result - an array of [numOfTeachingSets] arrays
return result;
}
//-----------------------------------------------------------
// Function:
// picks [cardsPerSet] number of unique item out of [availableChoices]
// each time an item is picked, this item is removed from [availableChoices]
//
// Important note: The number of card repetition is not really meaningful
// because if each round of picking produces unique sets,
// then the number of card repetition condition will be
// automatically satisfied.
//-----------------------------------------------------------
var pickOutUniqueNumberSet = function(availableChoices, cardsPerSet, disabledChoices){
if (cardsPerSet==0 || availableChoices.length==0){
return null;
}
var choosenSet = [];
var maxAttempts = 10000; //these 2 counter are used to prevent infinite looping
var attempts = 0;
for(var i=0;i<cardsPerSet;i++){
//items are choosen from [availableChoices] by their array index.
var randomIndex = Math.floor((Math.random() * availableChoices.length));
//repeatedly grab a random index from availableChoices till a unique one is selected
//unique item is an item that is not repeated in choosenSet, and its index is not in disabledChoices
while( (InArray(choosenSet, availableChoices[randomIndex]) || InArray(disabledChoices, randomIndex)) && attempts<maxAttempts){
randomIndex = Math.floor((Math.random() * availableChoices.length));
attempts++;
}
//Add this item to the chooseSet
choosenSet.push(availableChoices[randomIndex]);
//Add this item's index to disabledChoices
disabledChoices.push(randomIndex);
}
return choosenSet;
}
var InArray = function(array, itemToFind){
for(var i=0;i<array.length; i++){
if(array[i]==itemToFind){
return true;
}
}
return false;
}
//---------- Test --------
var teachingSets = shuffleCards(cards, numOfTeachingSets, numOfUniqueCardsPerTeachingSet, numOfCardRepetitionPerDay);
for(var i=0;i<teachingSets.length; i++){
document.write(teachingSets[i] + "<br>");
}

Comparing 2 arrays to output total integer

I have 2 arrays of numbers. I want to go through each array and find the number of times 1 number from each array adds up to the particular amount x.
If the particular amount x is reached as many times as another set number n then the function should print 'YES'. If x does not reach the set number of n then the function should print 'NO'.
The values of x , n and both arrays are in a string input. These values have been split into arrays as seen below in the code.
I have set up 2 for loops to run through each array and an if statement that checks for the condition of x meeting n.
The arrays I'm using in this code should print out the result of 'YES' however every time I run the code I'm getting 'NO' ? I've tried tinkering with the code but nothing has worked.
Any idea on where this code is broke and how to fix the problem?
Thanks :)
code:
var input = '2\n3 10\n2 1 3\n7 8 9';
function processData(input) {
var inputArray = input.split('\n');
var n = inputArray[1][0];
var x = inputArray[1].split(' ')[1];
var arrayA = inputArray[2].split(' ');
var arrayB = inputArray[3].split(' ');
var total = 0;
for(var i = 0; i < arrayA.length; i++) {
for(var j = 0; j < arrayB.length; j++) {
if(arrayA[i] + arrayB[j] == x) {
total = total + 1;
} if (total == n) {
return 'YES';
}
}
}
return 'NO';
}
console.log(processData(input));
arrayA[i] and arrayB[j] are strings, so arrayA[i] + arrayB[j] will be the concatenation of them (ex: '2' + '3' === '23').
If your logic is correct (i didn't quite understand what you are trying to do), it should be enough to convert them to numbers before adding them, using parseInt or some other method:
if(+arrayA[i] + (+arrayB[j]) == +x) { // used unary + to convert to number
total = total + 1;
} if (total == n) {
return 'YES';
}
PS: A cleaner version would be to convert each string in the array to number, but that involves more than adding 3 characters to your code.
PS2: You have a weird way of getting the input data. If you get it from another place in your JS code, you could simply pass it as an object with the relevant structure, otherwise you could pass it around in a more ... common format, like JSON.

Categories

Resources