Lottery with Supernumber - javascript

I came across the challenge of building a random numbers generator for the lottery.
6 numbers, which are between 1 and 49, none of which appears to be twice, in ascending order. One 7th number, the super-seven, not sorted, can't be one of the previous numbers.
<script type="text/javascript">
const numb = new Array();
for (var i = 0; i < 6; i++) {
numb[i] = Math.floor(49 * Math.random()) + 1;
//compare to existing numbs
for (var k = 0; k < numb.length - 1; k++) {
if (numb[i] == numb[k]) {
i--;
break;
}
}
}
let supNumb = new Array();
supNumb = Math.floor(49 * Math.random()) + 1;
for (var s = 0; s <= 1; s++) {
// compare supNumb to numb
for (var t = 0; t < numb.length - 1; t++) {
if (supNumb == numb[t]) {
s--;
break;
}
}
}
// SORT & DISPLAY NUMBERS
function sort(a, b) {
return a - b;
}
numb.sort(sort);
document.write("<p> " + numb);
document.write("<h4>" + "SuperSeven: " + supNumb);
</script>
I know by trying the super-seven supNumb is still giving out same numbers as in numb.
I can't get it to work and can't find anywhere this being mentioned.
Somebody here can look over it and let me know how I can compare supNumb to numb?
Is this even the right structure?
Thanks in advance!

You can make an infinit loop and break it if you find a valid number like so:
while(true){
supNumb = Math.floor(49 * Math.random()) + 1;
if(numb.indexOf(supNumb) < 0){
break;
}
}
Also better use indexOf so search in the array. It is much faster than plain JS.
https://www.w3schools.com/jsref/jsref_indexof_array.asp
You could even use the Set mechanics to achieve this. Sets can only store unique values. All duplicates will thereby be ignored:
var numbers = new Set(),
supNumb = 0;
while(numbers.size < 6){
numbers.add(Math.floor(49 * Math.random()) + 1);
}
while(true){
supNumb = Math.floor(49 * Math.random()) + 1;
if(!numbers.has(supNumb)) break;
}
var sortedNumbers = [...numbers].sort((a,b)=>{return a-b})
console.log(sortedNumbers, supNumb);
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Set

You have supNumb as an Array, I think it should be a scalar (single integer) as you are doing a compare against array member of your array numb
As well you'd have to regenerate via Random if the supNumb fails to pass he criteria 'it must be unique'

To sample non-repeating numbers there is a method called Fisher-Yates-Knuth shuffle. It is guaranteed to select 7 non-repeating numbers from 1...49 range, without any secondary checks.
In some pseudocode (sorry, don't know Javascript)
a = _.range(1, 50);
for i from nāˆ’1 downto 1 do
j ā† random integer such that 0 ā‰¤ j ā‰¤ i
exchange a[j] and a[i]
sort(a, 6); // sort first 6 elements
super = a[6];

Related

CodeSignal sumInRange challenge in JavaScript

I'm working on this CodeSignal exercise that says:
You have an array of integers nums and an array queries, where queries[i] is a pair of indices (0-based). Find the sum of the elements in nums from the indices at queries[i][0] to queries[i][1] (inclusive) for each query, then add all of the sums for all the queries together. Return that number modulo 10^9 + 7.
This is my code:
function solution(nums, queries) {
let accumulator = 0;
let M = 1000000007;
for(let i = 0; i < queries.length; i++){
accumulator += nums.slice(queries[i][0],queries[i][1]+1).reduce((a,b) => a+b);
}
return accumulator < 0 ? ((accumulator % M) + M) % M : accumulator%M;
}
It works perfectly, BUT the penultimate hidden test throws a timeout, and I'm out of ideas on how to make this faster.
Thanks in advance for any help you may provide.
PS: if you're wondering about the difference using modulo at the end, it's because it seems JS has a bug when using negative numbers.
As tflave pointed out, using a prefix sum made the code perform faster, and it didn't timeout. Here's the code if anyone needs it:
let pre = new Array(1000,0);
function preCompute(nums)
{
let n = nums.length;
pre[0] = nums[0];
for (let i = 1; i < n; i++) {
pre[i] = nums[i] + pre[i - 1];
}
}
function solution(nums, queries)
{
preCompute(nums);
let accumulator = 0;
let M = 1000000007;
for(let i = 0; i < queries.length; i++){
if (queries[i][0] === 0) {
accumulator += pre[queries[i][1]];
} else {
accumulator += pre[queries[i][1]] - pre[queries[i][0] - 1];
}
}
return accumulator < 0 ? ((accumulator % M) + M) % M : accumulator%M;
}

How to stop random letter picking from doing duplicate letters [duplicate]

I need help with writing some code that will create a random number from an array of 12 numbers and print it 9 times without dupes. This has been tough for me to accomplish. Any ideas?
var nums = [1,2,3,4,5,6,7,8,9,10,11,12];
var gen_nums = [];
function in_array(array, el) {
for(var i = 0 ; i < array.length; i++)
if(array[i] == el) return true;
return false;
}
function get_rand(array) {
var rand = array[Math.floor(Math.random()*array.length)];
if(!in_array(gen_nums, rand)) {
gen_nums.push(rand);
return rand;
}
return get_rand(array);
}
for(var i = 0; i < 9; i++) {
console.log(get_rand(nums));
}
The most effective and efficient way to do this is to shuffle your numbers then print the first nine of them. Use a good shuffle algorithm.What Thilo suggested will give you poor results. See here.
Edit
Here's a brief Knuth Shuffle algorithm example:
void shuffle(vector<int> nums)
{
for (int i = nums.size()-1; i >= 0; i--)
{
// this line is really shorthand, but gets the point across, I hope.
swap(nums[i],nums[rand()%i]);
}
}
Try this once:
//Here o is the array;
var testArr = [6, 7, 12, 15, 17, 20, 21];
shuffle = function(o){ //v1.0
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
shuffle(testArr);
This is relatively simple to do, the theory behind it is creating another array which keeps track of which elements of the array you have used.
var tempArray = new Array(12),i,r;
for (i=0;i<9;i++)
{
r = Math.floor(Math.random()*12); // Get a random index
if (tempArray[r] === undefined) // If the index hasn't been used yet
{
document.write(numberArray[r]); // Display it
tempArray[r] = true; // Flag it as have been used
}
else // Otherwise
{
i--; // Try again
}
}
Other methods include shuffling the array, removing used elements from the array, or moving used elements to the end of the array.
If I understand you correctly, you want to shuffle your array.
Loop a couple of times (length of array should do), and in every iteration, get two random array indexes and swap the two elements there. (Update: if you are really serious about this, this may not be the best algorithm).
You can then print the first nine array elements, which will be in random order and not repeat.
Here is a generic way of getting random numbers between min and max without duplicates:
function inArray(arr, el) {
for(var i = 0 ; i < arr.length; i++)
if(arr[i] == el) return true;
return false;
}
function getRandomIntNoDuplicates(min, max, DuplicateArr) {
var RandomInt = Math.floor(Math.random() * (max - min + 1)) + min;
if (DuplicateArr.length > (max-min) ) return false; // break endless recursion
if(!inArray(DuplicateArr, RandomInt)) {
DuplicateArr.push(RandomInt);
return RandomInt;
}
return getRandomIntNoDuplicates(min, max, DuplicateArr); //recurse
}
call with:
var duplicates =[];
for (var i = 1; i <= 6 ; i++) {
console.log(getRandomIntNoDuplicates(1,10,duplicates));
}
const nums = [1,2,3,4,5,6,7,8,9,10,11,12];
for(var i = 1 ; i < 10; i++){
result = nums[Math.floor(Math.random()*nums.length)];
const index = nums.indexOf(result);
nums.splice(index, 1);
console.log(i+' - '+result);
}

Random array between given range of integers, containing at least one instance of each integer in the range

I'm trying to generate an array that contains a random set of integers between a range that will contain at least one instance of each possible integer. I can generate an array with random integers between a range, but cannot figure out how to generate one that contains at least one instance of each integer in said range. I'm trying to generate an array that contains 84 keys with a range between 0 and 40 (including 0 and 40). The array should contain at least one instance of each possible integer in said range. This is the code that I have right now:
<script>
ints = [];
function sortInt(a, b) {
return a - b;
}
for (i=0; i<84; i++) {
ints.push(Math.round(Math.random() * 40));
}
ints.sort(sortInt);
for (s=0; s<ints.length; s++) {
document.write(ints[s] + '<br />');
}
</script>
Please try the below snippet
function generateNumbers(number, startRange, endRange) {
if (startRange > endRange) return generateNumbers(number, endRange, startRange);
const arr = [];
for (let i = startRange; i <= endRange; ++i) arr.push(i);
while(number > arr.length) {
const newNumber = Math.round(Math.random() * (endRange - startRange));
arr.push(newNumber);
}
arr.sort((a, b) => a - b);
return arr;
}
console.log(generateNumbers(84, 0, 40));
I think if it needs all the integers between a range then you can start with generating between the range. Then all the other numbers can be random. Finally just need to use sort() on the array.
Like this:
const generate = (till, count) => {
const array = Array.from(new Array(till + 1).keys());
for (let i = till; i < count; i++) {
array.push(Math.round(Math.random() * till));
}
return array.sort((a,b) => a - b);
}
const result = generate(40, 84);
console.log(result);
I hope that helps!
You can create random index to insert a number from the desired range:
if (i == randomIndex)
ints.push(startRange);
else
ints.push(Math.floor(Math.random() * endRange) + startRange);
An example:
ints = [];
let startRange = 1, endRange = 84;
let randomIndex = Math.floor(Math.random() * endRange) + startRange;
for (i=0; i < 84; i++) {
if (i == randomIndex)
ints.push(startRange);
else
ints.push(Math.floor(Math.random() * endRange) + startRange);
}
ints.sort((a,b) => a - b);
console.log(ints)
I'd use randojs.com for this. Grab a shuffled array from 0 to 40, then add 43 more random numbers between 0 and 40 to the array and sort:
var ints = randoSequence(40);
for(var i = 0; i < 43; i++) ints.push(rando(40));
console.log( ints.sort((a, b) => {return a - b;}) );
<script src="https://randojs.com/1.0.0.js"></script>

Perfect squares from odd numbers

In JavaScript, is there a more efficient way of calculating perfect squares working from odd numbers than this (the last perfect square stored in the array perfectSqrs is console.logged):
let n = 999,
oddNums = [],
i;
for (i = 3; i < n; i += 1) {
if (i % 2 !== 0) {
oddNums.push(i);
}
}
let oddLength = oddNums.length;
let perfectSqrs = [1],
j = 0;
while (j < oddLength - 1) {
perfectSqrs[j + 1] = perfectSqrs[j] + oddNums[j];
j += 1;
}
console.log(perfectSqrs[perfectSqrs.length - 1]);
Looks like you just want to generate an array of perfect squares? Perhaps you can do something like this:
var squares = [1];
var numSquares = 100;
for (var i=3; i<numSquares*2; i+=2) {
squares.push(squares[squares.length - 1] + i);
}
console.log(squares);
For people unclear about this algorithm, basically:
1
4 (1+3)
9 (1+3+5)
16 (1+3+5+7)
25 (1+3+5+7+9)
Perfect square is essentially the sum of odd numbers
Nothing to do with JS more with algorithms and logic. You can totally avoid the first loop and also avoid storing (memory efficiency) odd numbers. Start your second loop with 1 and iterate by incrementing by 2 instead of 1 (1,3,5,7,...).

pushing arrays in multidimensional array

I want to push arrays containing random numbers (0 to 10) into a bigger array once the total of its contents is about to exceed 30. But the output is messed up.
var bigarray = new Array();
var smallarray = new Array();
var randNum = 0;
var total = 0;
for (var i = 0; i<10; i++){
randNum = (10*Math.random()).toFixed(0);
total = total + randNum;
if(total>30) {
bigarray.push(smallarray)
smallarray.length=0;
smallarray.push(randNum);
total = randNum;
} else {
smallarray.push(randNum);
}
}
alert(" BIG ARRAY IS "+bigarray);
two wrong things are visible on the first sight in the code
(1) instead of
randNum = (10*Math.random()).toFixed(0);
you probably want
randNum = Math.floor(11*Math.random());
Math.floor instead of toFixed() - see #kennebec comment
11 instead of 10 to return numbers 0 to 10, as 0 <= Math.random() < 1
(2) the following line pushes (many times) the reference to the same smallarray object.
bigarray.push(smallarray);
In the next step you clear the array with smallarray.length = 0. Because the array is not copied to the bigarray, but only referenced, the generated items are lost.
EDIT: I read your question wrong - the rest of the answer is fixed
You probably want to push the duplicate of the smallarray into bigarray, so replace the line above with the following:
bigarray.push(smallarray.slice(0));
You need another loop inside the main one to populate the smallarray, something like:
var bigarray = new Array();
for (var i = 0; i<10; i++){
// moving the variable declarations inside this loop means they are re-set for each small array
var smallarray = new Array();
// create the first entry for the small array
var randNum = Math.floor(11*Math.random());
var total = randNum;
// loop to populate the small array
while(total <= 30){
smallarray.push(randNum);
randNum = Math.floor(11*Math.random());
total += randNum;
}
bigarray.push(smallarray)
}
I made changes to you code and came up with this.
var bigarray = [];
var smallarray = [];
var randNum = 0;
var total = 0;
for (var i = 0; i < 10; i += 1) {
randNum = Math.floor(10 * Math.random()); // you will never have a value of 10?
total = total + randNum;
if (total > 30) {
bigarray.push(smallarray.slice())
smallarray.length = 0;
smallarray.push(randNum);
total = randNum;
} else {
smallarray.push(randNum);
}
}
alert(" BIG ARRAY IS " + bigarray);
On jsfiddle
Things I changed were:
Ran the code through a beautifier
Changed your use of new Array to []
{} and []
Use {} instead of new Object(). Use [] instead of new Array().
Because Object and Array can be overwritten by the user
Changed ++ to += 1
This pattern can be confusing.
Check out Code Conventions for the JavaScript Programming Language and jslint
Added array.slice when you push smallarray to bigarray, this makes a copy in this case. It is important to understand how javascript works, read Is JavaScript a pass-by-reference or pass-by-value language? Without using slice, which makes a copy as the array only contains primitives, when you set the length of the array to 0, then the data was lost.
Changed your use of number.toFixed to Math.floor so that randNum remains a number
Note: Math.random returns a floating-point, pseudo-random number in the range [0, 1] that is, from 0 (inclusive) up to but not including 1 (exclusive)
Whether your code now produces your expected out, I can not be sure from your description but this should be a good starting point.
var bigarray = new Array();
var smallarray = new Array();
var randNum = 0;
var total = 0;
for (var i = 0; i < 10; i++) {
for (var j = 0; j < smallarray.length; j++) {
total = total + smallarray[j];
}
if (total <= 30)
{
randNum = Math.floor((Math.random() * 10) + 1);
smallarray.push(randNum);
}
else {
bigarray.push(smallarray.slice(0));
smallarray.length = 0;
}
total = 0;
}
alert(" BIG ARRAY IS " + bigarray);

Categories