Split a range of number to a specific number of intervals - javascript

I have an interval [0; max] and I want to split it into a specific number of sub-intervals. For this, i wrote a function called getIntervalls(max, nbIntervals) where max is the max element in my first interval and nbIntervals is the number of expected sub-intervals.
For example:
getIntervalls(3, 2) should return [[0,1], [2,3]],
getIntervalls(6, 2) should return [[0,3], [4,6]],
getIntervalls(8, 3) should return [[0,2], [3,5], [6,8]],
getIntervalls(9, 3) should return [[0,3], [4,7], [8,9]],
Here is my function:
function getIntervalls(max, nbIntervalls) {
var size = Math.ceil(max / nbIntervalls);
var result = [];
if (size > 1) {
for (let i = 0; i < nbIntervalls; i++) {
var inf = i + i * size;
var sup = inf + size < max ? inf + size: max;
result .push([inf, sup]);
}
} else {
result.push([0, max]);
}
return result;
}
console.log(JSON.stringify(getIntervalls(7, 2)));
It work properly, and shows this output:
[[0,4],[5,7]]
When I change the parameters to 7 and 3, it shows:
[[0,3],[4,7],[8,7]]
instead of
[[0,2],[3,5],[6,7]]
Would anyone can help me? Thank you in advance. An ES6 syntax will be appreciated! :)

You need to use Math.round() for take the nearest integer of the decimal number of the size of interval. Also, you need to descrease a one the max for size calculation to take account of the effective number of interval.
Here the modification of your code :
function getIntervalls(max, nbIntervalls) {
var size = Math.round((max-1) / nbIntervalls);
var result = [];
for (let i = 0; i < nbIntervalls; i++) {
var inf = i + i * size;
var sup = inf + size < max ? inf + size: max;
result.push([inf, sup]);
if(inf >= max || sup >= max)break;
}
return result;
}
Note that it respect the wanted number of interval, so some case of couple of number can result
[..., [n-2,n-1], [n,n]].
Hope this helps!

You could check if i is zero for first element and if next increment is larger then max for second element. Also you can check if first element is smaller then max.
function getIntervalls(max, nInt) {
const c = Math.floor(max / nInt);
const r = [];
for (var i = 0; i <= max; i += c) {
const a = i == 0 ? i : i += 1;
const b = i + c > max ? max : i + c;
if (a < max) r.push([a, b])
}
return r;
}
console.log(JSON.stringify(getIntervalls(3, 2)));
console.log(JSON.stringify(getIntervalls(6, 2)));
console.log(JSON.stringify(getIntervalls(8, 3)));
console.log(JSON.stringify(getIntervalls(9, 3)));
console.log(JSON.stringify(getIntervalls(7, 2)));
console.log(JSON.stringify(getIntervalls(7, 3)));

You need to change the size calculation from Math.ceil() to Math.floor(), because of ceil it takes size +1 than what you need.
I have made modification to your code, here it will work.
function getIntervalls(max, nbIntervalls) {
var size = Math.floor(max / nbIntervalls);
var result = [];
if (size > 0) {
for (let i = 0; i < nbIntervalls; i++) {
var inf = i + i * size;
var sup = inf + size < max ? inf + size : max;
result .push([inf, sup]);
if (sup >= max) {
break;
}
}
} else {
result.push([0, max]);
}
return result;
}
console.log(JSON.stringify(getIntervalls(10, 5)));
Hope this helps!

For me, this is the perfect function for that.
It allows you to get the intervals between two numbers, and the last interval always goes to the max.
function getIntervals(min, max, nbIntervals) {
let size = Math.floor((max - min) / nbIntervals);
let result = [];
if (size <= 0) return [min, max];
for (let i = 0; i < nbIntervals; i++) {
let inf = min + (i * size);
let sup = ((inf + size) < max) ? inf + size : max;
if (i === (nbIntervals - 1)) {
if (sup < max) sup = max;
}
result.push([inf, sup]);
if (sup >= max) break;
}
return result;
}

Related

How to find a largest number in an array?

function myarray(min, max) {
var points = [];
for (var i = 0; i < 10; i++) {
points.push(Math.round(Math.random() * (1000 - 100 + 1) + 100));
points.join('<br>');
var largest = Math.max.apply(0, points);
}
return points
}
console.log(myarray());
My task is pretty simple, I want to create 10 random numbers from 1 to 1000 in an array and then print the highest one. I think I am pretty close but when I run this I get undefined.
How can I fix this? and what is undefined?
You can compare points to the largest number. Try the below snippet.
function myarray(min, max) {
var points = [];
var largest = 0;
for (var i = 0; i < 10; i++) {
points.push(Math.round(Math.random() * (1000 - 100 + 1) + 100));
if ( points[i] > largest ) {
var largest = points[i];
}
}
console.log(points);
console.log(largest);
}
myarray();
As per OP comment.
function myarray(min, max) {
var points = [ 521,338,761,834,561,842,177,862,173 ];
var largest = 0;
for (var i = 0; i < 10; i++) {
if ( points[i] > largest ) {
var largest = points[i];
}
}
console.log(points);
console.log(largest);
}
myarray();
All you need to do is move the call to Math.max.apply(0, points) outside the loop which is building the array and return that. Also, no need for the points.join line at all
function myarray(min, max) {
var points = [];
for (var i = 0; i < 10; i++) {
points.push(Math.round(Math.random() * (1000 - 100 + 1) + 100));
}
var largest = Math.max.apply(null, points);
return largest
}
console.log(myarray());
let arr = [1,2,3,5,25,35,43,75,100,35,3244,345,535,532]
let maxnum = arr.reduce((pre,cur) =>{
if(pre <= cur){
pre = cur
}
return pre
},0)
Because I love one-line solutions :)
console.log(Math.max(...Array.apply(null, Array(10)).map(
x=>Math.round(Math.random() * (1000 - 100 + 1) + 100)
)))

Javascript dropdown options 0-100 increment by .5

I have a javascript function that is creating the values for a dropdown on my page. I am currently incrementing by 5, (0-100).
I am trying to change this to increment by .5 instead but it keeps just returning 0-100 with no increment.
My expected output is 0,.5,1,1.5,2,2.5 ... 100.
Here is my function so far:
/**
* Generate our possible error scores
*/
function generateErrorScores() {
var min = 0,
max = 100,
multiplier = 5, // Tried .5 here
list = [];
// Loop between min and max, increment by multiplier
for (var i = min; i <= max; i++) {
if (i % multiplier === 0) {
list.push(i);
}
}
return list;
}
console.log(generateErrorScores())
Fiddle: http://jsfiddle.net/3y451jga/
I have a feeling its if (i % multiplier === 0) { causing the problem but I am not sure how to adapt it to the .5 increments.
If all you want is the list [0, 0.5, 1, 1.5, ..., 100] you could do:
/**
* Generate our possible error scores
*/
function generateErrorScores() {
const multiplier = 0.5
return [...Array((100 / multiplier) + 1)].map((x, i) => i * multiplier)
}
console.log(generateErrorScores())
I think it would be easier to just do this
for (var i = min; i <= max; i+=0.5) {
list.push(i);
}
The if (i % multiplier === 0) serves no purpose. That works if you need multipliers off a list, but in this case you need fractions.
Interestingly, your comment is correct ("increment by multiplier") but the code is not doing that. A valid solution would be something like this:
function generateErrorScores() {
var min = 0,
max = 100,
segment = .5,
list = [];
// Loop between min and max, increment by segment
for (var i = min; i <= max; i += segment) {
list.push(i);
}
return list;
}
console.log(generateErrorScores())
function generateErrorScores() {
var min = 0,
max = 100,
increment = 0.5,
list = [];
// Loop between min and max, increment by multiplier
for (var i = min; i <= max; i = i + increment) {
list.push(i);
}
return list;
}
console.log(generateErrorScores());
You can just increment the i by 0.5 and you will get your expected output, there is no need for extra check here.
for (var i = min; i <= max; i+=0.5) {
/**
* Generate our possible error scores
*/
function generateErrorScores() {
var min = 0,
max = 100,
multiplier = 0.5,
list = [];
// Loop between min and max, increment by multiplier
for (var i = min; i <= max; i += 0.5) {
list.push(i);
}
return list;
}
console.log(generateErrorScores())

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

Random number, which is not equal to the previous number

I need to get random number, but it should not be equal to the previous number. Here is my piece of the code. But it doesn't work.
function getNumber(){
var min = 0;
var max = 4;
var i;
i = Math.floor(Math.random() * (max - min)) + min;
if (i=== i) {
i = Math.floor(Math.random() * (max - min)) + min;
}
return i;
};
console.log(getNumber());
This answer presents three attempts
A simple version with a property of the function getNumber, last, which stores the last random value.
A version which uses a closure over the min and max values with raising an exception if max is smaller than min.
A version which combines the closure and the idea of keeping all random values and use it as it seems appropriate.
One
You could use a property of getNumber to store the last number and use a do ... while loop.
function getNumber() {
var min = 0,
max = 4,
random;
do {
random = Math.floor(Math.random() * (max - min)) + min;
} while (random === getNumber.last);
getNumber.last = random;
return random;
};
var i;
for (i = 0; i < 100; i++) {
console.log(getNumber());
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
Two
Another proposal with a closure over the interval and the last random value.
function setRandomInterval(min, max) {
var last;
if (min >= max) {
throw 'Selected interval [' + min + ', ' + max + ') does not work for random numbers.';
}
return function () {
var random;
do {
random = Math.floor(Math.random() * (max - min)) + min;
} while (random === last);
last = random;
return random;
};
}
var i,
getRandom = setRandomInterval(0, 4);
for (i = 0; i < 100; i++) {
console.log(getRandom());
}
setRandomInterval(4, 4); // throw error
.as-console-wrapper { max-height: 100% !important; top: 0; }
Three
This proposal uses the idea to minimise the call of a new random number. It works with two variables, value for the continuing same random value and count for saving the count of the same value.
The function looks first if the saved count is given and if the value is not equal with the last value. If that happens, the saved value is returned and count is decremented.
Otherwise a new random numner is generated and checked as above (first proposal). If the number is equal to the last value, the count is incremented and it goes on with generating a new random value.
As result, almost all previous generated random values are used.
function setRandomInterval(min, max) {
var last, // keeping the last random value
value, // value which is repeated selected
count = 0, // count of repeated value
getR = function () { return Math.floor(Math.random() * (max - min)) + min; };
if (min >= max) {
throw 'Selected interval [' + min + ', ' + max + ') does not work for random numbers.';
}
return function () {
var random;
if (count && value !== last) {
--count;
return last = value;
}
random = getR();
while (random === last) {
value = random;
++count;
random = getR();
}
return last = random;
};
}
var i,
getRandom = setRandomInterval(0, 4);
for (i = 0; i < 100; i++) {
console.log(getRandom());
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
The following method generates a new random number in the [min, max] range and makes sure that this number differs from the previous one, without looping and without recursive calls (Math.random() is called only once):
If a previous number exists, decrease max by one
Generate a new random number in the range
If the new number is equal to or greater than the previous one, add one
(An alternative: If the new number is equal to the previous one, set it to max + 1)
In order to keep the previous number in a closure, getNumber can be created in an IIFE:
// getNumber generates a different random number in the inclusive range [0, 4]
var getNumber = (function() {
var previous = NaN;
return function() {
var min = 0;
var max = 4 + (!isNaN(previous) ? -1 : 0);
var value = Math.floor(Math.random() * (max - min + 1)) + min;
if (value >= previous) {
value += 1;
}
previous = value;
return value;
};
})();
// Test: generate 100 numbers
for (var i = 0; i < 100; i++) {
console.log(getNumber());
}
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
The [min, max] range is made inclusive by adding 1 to max - min in the following statement:
var value = Math.floor(Math.random() * (max - min + 1)) + min;
This is not a requirement in the question but it feels more natural to me to use an inclusive range.
First of all function should compare with previous value, now We have only i variable which is compared to itself. To be sure that we not have previous value we need to do loop inside ( recursive in my solution ), because single if statement not give us sure that second random will be not the same ( exists chance on that ). Your number set is very small so chance for collision is high and it is possible that loop needs few executions.
function getNumber(prev){
var min = 0;
var max = 4;
var next;
next = Math.floor(Math.random() * (max - min)) + min;
if (next===prev) {
console.log("--run recursion. Our next is ="+next); //log only for test case
next = getNumber(prev); //recursive
}
return next;
};
//test 100 times
var num=0;
for ( var i=0; i<100; i++){
num=getNumber(num);
console.log(num);
}
As You can see in tests we never have two the same values next to each other. I also added some console.log to show how many times recursion needs to run to find next number which is different then previous one.
A general solution
Keep track of the last generated number. When generating a new number, check that it differs from the last one. If not, keep generating new numbers until it is different, then output it.
Working demo
var getNumber = (function(){
var min = 0;
var max = 4;
var last = -1;
return function(){
var current;
do{
// draw a random number from the range [min, max]
current = Math.floor(Math.random() * (max + 1 - min)) + min;
} while(current === last)
return (last = current);
}
})();
// generate a sequence of 100 numbers,
// see that they all differ from the last
for(var test = [], i = 0; i < 100; i++){
test[i] = getNumber();
}
console.log(test);
Comment about computational efficiency
As discussed in comments and other answers, a potential drawback of the approach above is that it may require several attempts at generating a random number if the generated number equals the previous. Note that the probability of needing many attempts is quite low (it follows a rapidly declining geometric distribution). For practical purposes, this is not likely to have any noticeable impact.
However, it is possible to avoid making several attempts at generating a new random number by directly drawing a random number from the set of numbers in the range [min, max] excluding the previously drawn number: This is well demonstrated in the answer by #ConnorsFan, where only one random number is generated at each function call, while randomness is still preserved.
You'll need a variable with a greater scope than the variables local to your getNumber function. Try:
var j;
function getNumber(){
var min = 0;
var max = 4;
var i = Math.floor(Math.random() * (max - min)) + min;
if (j === i) {
i = getNumber();
}
j = i;
return i;
};
Remove the previous value from the set of possible values right from the start.
function getNumber(previous) {
var numbers = [0, 1, 2, 3, 4];
if (previous !== undefined) {
numbers.splice(numbers.indexOf(previous), 1);
}
var min = 0;
var max = numbers.length;
var i;
i = Math.floor(Math.random() * (max - min)) + min;
return numbers[i];
};
//demonstration. No 2 in a row the same
var random;
for (var i = 0; i < 100; i++) {
random = getNumber(random);
console.log(random);
}
You can use an implementation of #NinaScholz pattern, where the previous value is stored as property of the calling function, substituting conditional logic to increment or decrement current return value for a loop.
If the current value is equal to the previously returned value, the current value is changed during the current function call, without using a loop or recursion, before returning the changed value.
var t = 0;
function getNumber() {
var min = 0,
max = 4,
i = Math.floor(Math.random() * (max - min)) + min;
console.log(`getNumber calls: ${++t}, i: ${i}, this.j: ${this.j}`);
if (isNaN(this.j) || this.j != i) {
this.j = i;
return this.j
} else {
if (this.j === i) {
if (i - 1 < min || i + 1 < max) {
this.j = i + 1;
return this.j
}
if (i + 1 >= max || i - 1 === min) {
this.j = i - 1;
return this.j
}
this.j = Math.random() < Math.random() ? --i : ++i;
return this.j
}
}
};
for (var len = 0; len < 100; len++) {
console.log("random number: ", getNumber());
}
This solution uses ES6 generators and avoids generating random numbers until you find one that complies with the precondition (two correlated numbers must be different).
The main idea is to have an array with the numbers and an array with indexes. You then get a random index (to comply with the precondition, the indexes' array will be the result of filtering the array of indexes with the previous selected index). The return value will be the number that correspond to the index in the numbers' array.
function* genNumber(max = 4) {// Assuming non-repeating values from 0 to max
let values = [...Array(max).keys()],
indexes = [...Array(max).keys()],
lastIndex,
validIndexes;
do {
validIndexes = indexes.filter((x) => x !== lastIndex);
lastIndex = validIndexes[Math.floor(Math.random() * validIndexes.length)];
yield values[lastIndex];
} while(true);
}
var gen = genNumber();
for(var i = 0; i < 100; i++) {
console.log(gen.next().value);
}
Here's the fiddle in case you want to check the result.
Save the previous generated random number in a array check the new number with the existing number you can prevent duplicate random number generation.
// global variables
tot_num = 10; // How many number want to generate?
minimum = 0; // Lower limit
maximum = 4; // upper limit
gen_rand_numbers = []; // Store generated random number to prevent duplicate.
/*********** **This Function check duplicate number** ****************/
function in_array(array, el) {
for (var i = 0; i < array.length; i++) {
if (array[i] == el) {
return true;
}
}
return false;
}
/*--- This Function generate Random Number ---*/
function getNumber(minimum, maximum) {
var rand = Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
if (gen_rand_numbers.length <= (maximum - minimum)) {
if (!in_array(gen_rand_numbers, rand)) {
gen_rand_numbers.push(rand);
//alert(rand)
console.log(rand);
return rand;
} else {
return getNumber(minimum, maximum);
}
} else {
alert('Final Random Number: ' + gen_rand_numbers);
}
}
/*--- This Function call random number generator to get more than one random number ---*/
function how_many(tot_num) {
for (var j = 0; j < tot_num; j++) {
getNumber(minimum, maximum);
}
}
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js" > </script>
<input type = "button" onclick = "how_many(4)" value = "Random Number" >
You can use a augmented implementation of a linear congruential generator.
A linear congruential generator (LCG) is an algorithm that yields a sequence of pseudo-randomized numbers calculated with a discontinuous piecewise linear equation.
The following function returns a seeded random number in conjunction with a min and max value:
Math.seededRandom = function(seed, min, max) {
max = max || 1;
min = min || 0;
// remove this for normal seeded randomization
seed *= Math.random() * max;
seed = (seed * 9301 + 49297) % 233280;
let rnd = seed / 233280.0;
return min + rnd * (max - min);
};
In your case, because you never want the new number to be the same as the previous, then you can pass the previously generated number as the seed.
Here is an example of this follows which generates 100 random numbers:
Math.seededRandom = function(seed, min, max) {
max = max || 1;
min = min || 0;
// remove this for normal seeded randomization
seed *= Math.random() * max;
seed = (seed * 9301 + 49297) % 233280;
let rnd = seed / 233280.0;
return min + rnd * (max - min);
};
let count = 0;
let randomNumbers = [];
let max = 10;
do {
let seed = (randomNumbers[randomNumbers.length -1] || Math.random() * max);
randomNumbers.push(Math.seededRandom(seed, 0, max));
count++;
} while (count < 100)
console.log(randomNumbers);
A fun answer, to generate numbers from 0 to 4 in one line:
console.log(Math.random().toString(5).substring(2).replace(/(.)\1+/g, '$1').split('').map(Number));
Explanation:
Math.random() //generate a random number
.toString(5) //change the number to string, use only 5 characters for it (0, 1, 2, 3, 4)
.substring(2) //get rid of '0.'
.replace(/(.)\1+/g, '$1') //remove duplicates
.split('') //change string to array
.map(Number) //cast chars into numbers
And a longer version with generator:
let Gen = function* () {
const generateString = (str) => str.concat(Math.random().toString(5).substring(2)).replace(/(.)\1+/g, '$1');
let str = generateString('');
let set = str.split('').map(Number);
while (true) {
if (set.length === 0) {
str = generateString(str).substring(str.length);
set = str.split('').map(Number);
}
yield set.pop();
}
}
let gen = Gen();
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
function getNumber(){
var min = 0;
var max = 4;
var i;
i = Math.floor(Math.random() * (max - min)) + min;
while(i==getNumber.last)
i = Math.floor(Math.random() * (max - min)) + min;
getNumber.last=i;
return i;
};
console.log(getNumber());
Try this
var prev_no = -10;
function getNumber(){
var min = 0;
var max = 4;
var i;
i = Math.floor(Math.random() * (max - min)) + min;
while (i == prev_no) {
i = Math.floor(Math.random() * (max - min)) + min;
prev_no = i;
}
return i;
};
console.log(getNumber());
You can use Promise, Array.prototype.forEach(), setTimeout. Create and iterate an array having .length set to max; use setTimeout within .forEach() callback with duration set to a random value to push the index of the array to a new array for non-uniform distribution of of the indexes within the new array. Return resolved Promise from getNumber function where Promise value at .then() will be an array of .length max having random index from .forEach() callback as values without duplicate entries.
function getNumber(max) {
this.max = max;
this.keys = [];
this.arr = Array.from(Array(this.max));
this.resolver = function getRandom(resolve) {
this.arr.forEach(function each(_, index) {
setTimeout(function timeout(g) {
g.keys.push(index);
if (g.keys.length === g.max) {
resolve(g.keys)
};
}, Math.random() * Math.PI * 100, this);
}, this)
};
this.promise = new Promise(this.resolver.bind(this));
}
var pre = document.querySelector("pre");
var random1 = new getNumber(4);
random1.promise.then(function(keys) {
pre.textContent += keys.length + ":\n";
keys.forEach(function(key) {
pre.textContent += key + " ";
})
});
var random2 = new getNumber(1000);
random2.promise.then(function(keys) {
pre.textContent += "\n\n";
pre.textContent += keys.length + ":\n";
keys.forEach(function(key) {
pre.textContent += key + " ";
})
});
pre {
white-space: pre-wrap;
width: 75vw;
}
<pre></pre>
I'm surprised no one has suggested a simple solution like this:
function getRandomNum(min, max, exclude) {
if (Number.isNaN(exclude)) exclude = null;
let randomNum = null;
do {
randomNum = Math.floor(min + Math.random() * (max + 1 - min));
} while (randomNum === exclude);
return randomNum;
}
Note that "exclude" is optional. You would use it like this:
// Pick 2 unique random numbers between 1 and 10
let firstNum = getRandomNum(1, 10);
let secondNum = getRandomNum(1, 10, firstNum);
You can give it a try here:
function getRandomNum(min, max, exclude) {
if (Number.isNaN(exclude)) exclude = null;
let randomNum = null;
do {
randomNum = Math.floor(min + Math.random() * (max + 1 - min));
} while (randomNum === exclude);
return randomNum;
}
// Pick 2 unique random numbers between 1 and 10
let firstNum = getRandomNum(1, 10);
let secondNum = getRandomNum(1, 10, firstNum);
// Output the numbers
document.write(firstNum + ' and ' + secondNum);
You can't achieve this unless you you do a database query to check existence of the new number. If existing, repeat the process.
There is an architectural possibility of making unique random number is to generate two random number and combine the strings.
For example:
rand_num1 = rand(5);
rand_num2 = rand(4);
then combine rand_num1 and rand_num2 which is more like unique
Practical example:
(23456)(2345)
(23458)(1290)
(12345)(2345)
Also increase the number of digits to reduce repetition.

How to find the least common multiple of a range of numbers?

Given an array of two numbers, let them define the start and end of a range of numbers. For example, [2,6] means the range 2,3,4,5,6. I want to write javascript code to find the least common multiple for the range. My code below works for small ranges only, not something like [1,13] (which is the range 1,2,3,4,5,6,7,8,9,10,11,12,13), which causes a stack overflow. How can I efficiently find the least common multiple of a range?
function leastCommonMultiple(arr) {
var minn, max;
if ( arr[0] > arr[1] ) {
minn = arr[1];
max = arr[0];
} else {
minn = arr[0];
max = arr[1];
}
function repeatRecurse(min, max, scm) {
if ( scm % min === 0 && min < max ) {
return repeatRecurse(min+1, max, scm);
} else if ( scm % min !== 0 && min < max ) {
return repeatRecurse(minn, max, scm+max);
}
return scm;
}
return repeatRecurse(minn, max, max);
}
I think this gets the job done.
function leastCommonMultiple(min, max) {
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.push(i);
}
return arr;
}
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
var multiple = min;
range(min, max).forEach(function(n) {
multiple = lcm(multiple, n);
});
return multiple;
}
leastCommonMultiple(1, 13); // => 360360
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
LCM function for a range [a, b]
// Euclid algorithm for Greates Common Divisor
function gcd(a, b)
{
return !b ? a : gcd(b, a % b);
}
// Least Common Multiple function
function lcm(a, b)
{
return a * (b / gcd(a,b));
}
// LCM of all numbers in the range of arr=[a, b]
function range_lcm(arr)
{
// Swap [big, small] to [small, big]
if(arr[0] > arr[1]) (arr = [arr[1], arr[0]]);
for(x = result = arr[0]; x <= arr[1]; x++) {
result = lcm(x, result);
}
return result;
}
alert(range_lcm([8, 5])); // Returns 840
As this question has recently been revived, here's what I think is a simpler take on the question, writing very simple helper functions to calculate the greatest common divisor of two integers (gcd), to calculate the least common multiple of two integers (lcm), to calculate the least common multiple of an array of integers (lcmAll), to generate the range of integers between two given integers (rng), and finally, in our main function, to calculate the least common multiple of the range of integers between two given integers (lcmRng):
const gcd = (a, b) => b == 0 ? a : gcd (b, a % b)
const lcm = (a, b) => a / gcd (a, b) * b
const lcmAll = (ns) => ns .reduce (lcm, 1)
const rng = (lo, hi) => [...Array (hi - lo + 1)] .map ((_, i) => lo + i)
const lcmRng = (lo, hi) => lcmAll (rng (lo, hi))
console .log (lcmRng (1, 13))
All of these functions are simple. Although the question was tagged recursion, only gcdis recursive. If this is an attempt to play with recursion, we could rewrite lcmAll in a recursive manner with something like this:
const lcmAll = (ns) =>
ns.length == 0
? 1
: lcm(ns[0], lcmAll(ns .slice (1)))
Although I'm a big fan of recursion, I see no other reason to choose the recursive version here over the reduce one. In this case, reduce is cleaner.
And finally, if you really want the API originally requested where the range bounds are passed in an array, you could write one more wrapper:
const leastCommonMultiple = ([lo, hi]) => lcmRng (lo, hi)
leastCommonMultiple ([1, 13]) //=> 360360
I found the other answers to be somewhat confusing while I was figuring out the best way to do this with just two numbers, so I looked found the most optimal solution on Wikipedia.
https://en.wikipedia.org/wiki/Least_common_multiple#Calculation
The most efficient way to find the least common multiple of two numbers is (a * b) / greatestCommonDivisor(a, b);
To do this we need to calculate the greatest common denominator. The most efficient way to do that is using Euclid's algorithm.
https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclid's_algorithm
Here is the complete solution for two numbers in case anyone else lands on this question but only needs to calculate for two numbers:
const leastCommonMultiple = (a, b) => (a * b) / greatestCommonDivisor(a, b);
const greatestCommonDivisor = (a, b) => {
const remainder = a % b;
if (remainder === 0) return b;
return greatestCommonDivisor(b, remainder);
};
Mine is not as fancy as the other answers but I think it is easy to read.
function smallestCommons(arr) {
//order our array so we know which number is smallest and which is largest
var sortedArr = arr.sort(sortNumber),
//the smallest common multiple that leaves no remainder when divided by all the numbers in the rang
smallestCommon = 0,
//smallest multiple will always be the largest number * 1;
multiple = sortedArr[1];
while(smallestCommon === 0) {
//check all numbers in our range
for(var i = sortedArr[0]; i <= sortedArr[1]; i++ ){
if(multiple % i !== 0 ){
//if we find even one value between our set that is not perfectly divisible, we can skip to the next multiple
break;
}
//if we make it all the way to the last value (sortedArr[1]) then we know that this multiple was perfectly divisible into all values in the range
if(i == sortedArr[1]){
smallestCommon = multiple;
}
}
//move to the next multiple, we can just add the highest number.
multiple += sortedArr[1];
}
console.log(smallestCommon);
return smallestCommon;
}
function sortNumber(a, b) {
return a - b;
}
smallestCommons([1, 5]); // should return 60.
smallestCommons([5, 1]); // should return 60.
smallestCommons([1, 13]); // should return 360360.
smallestCommons([23, 18]); // should return 6056820.
Edit: Turned answer into snippet.
This is a non-recursive version of your original approach.
function smallestCommons(arr) {
// Sort the array
arr = arr.sort(function (a, b) {return a - b}); // numeric comparison;
var min = arr[0];
var max = arr[1];
var numbers = [];
var count = 0;
//Here push the range of values into an array
for (var i = min; i <= max; i++) {
numbers.push(i);
}
//Here freeze a multiple candidate starting from the biggest array value - call it j
for (var j = max; j <= 1000000; j+=max) {
//I increase the denominator from min to max
for (var k = arr[0]; k <= arr[1]; k++) {
if (j % k === 0) { // every time the modulus is 0 increase a counting
count++; // variable
}
}
//If the counting variable equals the lenght of the range, this candidate is the least common value
if (count === numbers.length) {
return j;
}
else{
count = 0; // set count to 0 in order to test another candidate
}
}
}
alert(smallestCommons([1, 5]));
Hey I came across this page and wanted to share my solution :)
function smallestCommons(arr) {
var max = Math.max(arr[0], arr[1]),
min = Math.min(arr[0], arr[1]),
i = 1;
while (true) {
var count = 0;
for (j = min; j < max; j++) {
if (max * i % j !== 0) {
break;
}
count++;
}
if (count === (max - min)) {
alert(max * i);
return max * i;
}
i++;
}
}
smallestCommons([23, 18]);
function leastCommonMultiple(arr) {
/*
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.push(i);
}
return arr;
}
*/
var min, range;
range = arr;
if(arr[0] > arr[1]){
min = arr[1];
}
else{
min = arr[0]
}
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
var multiple = min;
range.forEach(function(n) {
multiple = lcm(multiple, n);
});
return multiple;
}
console.log( leastCommonMultiple([1, 13]) )
Well played on the solution. I think I got one that might be abit shorter just for future reference but ill definatly look into yours
function LCM(arrayRange) {
var newArr = [];
for (var j = arrayRange[0]; j <= arrayRange[1]; j++){
newArr.push(j);
}
var a = Math.abs(newArr[0]);
for (var i = 1; i < newArr.length; i++) {
var b = Math.abs(newArr[i]),
c = a;
while (a && b) {
a > b ? a %= b : b %= a;
}
a = Math.abs(c * newArr[i] / (a + b))
}
return console.log(a);
}
LCM([1,5]);
You may have originally had a stack overflow because of a typo: you switched between min and minn in the middle of repeatRecurse (you would have caught that if repeatRecurse hadn’t been defined in the outer function). With that fixed, repeatRecurse(1,13,13) returns 156.
The obvious answer to avoiding a stack overflow is to turn a recursive function into a non-recursive function. You can accomplish that by doing:
function repeatRecurse(min, max, scm) {
while ( min < max ) {
while ( scm % min !== 0 ) {
scm += max;
}
min++;
}
}
But perhaps you can see the mistake at this point: you’re not ensuring that scm is still divisible by the elements that came before min. For example, repeatRecurse(3,5,5)=repeatRecurse(4,5,15)=20. Instead of adding max, you want to replace scm with its least common multiple with min. You can use rgbchris’s gcd (for integers, !b is the same thing as b===0). If you want to keep the tail optimization (although I don’t think any javascript engine has tail optimization), you’d end up with:
function repeatRecurse(min, max, scm) {
if ( min < max ) {
return repeatRecurse(min+1, max, lcm(scm,min));
}
return scm;
}
Or without the recursion:
function repeatRecurse(min,max,scm) {
while ( min < max ) {
scm = lcm(scm,min);
min++;
}
return scm;
}
This is essentially equivalent to rgbchris’s solution. A more elegant method may be divide and conquer:
function repeatRecurse(min,max) {
if ( min === max ) {
return min;
}
var middle = Math.floor((min+max)/2);
return lcm(repeatRecurse(min,middle),repeatRecurse(middle+1,max));
}
I would recommend moving away from the original argument being an array of two numbers. For one thing, it ends up causing you to talk about two different arrays: [min,max] and the range array. For another thing, it would be very easy to pass a longer array and never realize you’ve done something wrong. It’s also requiring several lines of code to determine the min and max, when those should have been determined by the caller.
Finally, if you’ll be working with truly large numbers, it may be better to find the least common multiple using the prime factorization of the numbers.
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.push(i);
}
return arr;
}
function gcd (x, y) {
return (x % y === 0) ? y : gcd(y, x%y);
}
function lcm (x, y) {
return (x * y) / gcd(x, y);
}
function lcmForArr (min, max) {
var arr = range(min, max);
return arr.reduce(function(x, y) {
return lcm(x, y);
});
}
range(10, 15); // [10, 11, 12, 13, 14, 15]
gcd(10, 15); // 5
lcm(10, 15); // 30
lcmForArr(10, 15); //60060
How about:
// Euclid Algorithm for the Greatest Common Denominator
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
// Euclid Algorithm for the Least Common Multiple
function lcm(a, b) {
return a * (b / gcd(a, b));
}
// LCM of all numbers in the range of arr = [a, b];
function smallestCommons(arr) {
var i, result;
// large to small - small to large
if (arr[0] > arr[1]) {
arr.reverse();
} // only happens once. Means that the order of the arr reversed.
for (i = result = arr[0]; i <= arr[1]; i++) { // all numbers up to arr[1] are arr[0].
result = lcm(i, result); // lcm() makes arr int an integer because of the arithmetic operator.
}
return result;
}
smallestCommons([5, 1]); // returns 60
function lcm(arr) {
var max = Math.max(arr[0],arr[1]),
min = Math.min(arr[0],arr[1]),
lcm = max;
var calcLcm = function(a,b){
var mult=1;
for(var j=1; j<=a; j++){
mult=b*j;
if(mult%a === 0){
return mult;
}
}
};
for(var i=max-1;i>=min;i--){
lcm=calcLcm(i,lcm);
}
return lcm;
}
lcm([1,13]); //should return 360360.
/*Function to calculate sequential numbers
in the range between the arg values, both inclusive.*/
function smallestCommons(arg1, arg2) {
if(arg1>arg2) { // Swap arg1 and arg2 if arg1 is greater than arg2
var temp = arg1;
arg1 = arg2;
arg2 =temp;
}
/*
Helper function to calculate greatest common divisor (gcd)
implementing Euclidean algorithm */
function gcd(a, b) {
return b===0 ? a : gcd(b, a % b);
}
/*
Helper function to calculate lowest common multiple (lcm)
of any two numbers using gcd function above */
function lcm(a,b){
return (a*b)/gcd(a,b);
}
var total = arg1; // copy min value
for(var i=arg1;i<arg2;i++){
total = lcm(total,i+1);
}
//return that total
return total;
}
/*Yes, there are many solutions that can get the job done.
Check this out, same approach but different view point.
*/
console.log(smallestCommons(13,1)); //360360
Here's my solution. I hope you will find it easy to follow:
function smallestCommons(arr) {
var min = Math.min(arr[0], arr[1]);
var max = Math.max(arr[0], arr[1]);
var smallestCommon = min * max;
var doneCalc = 0;
while (doneCalc === 0) {
for (var i = min; i <= max; i++) {
if (smallestCommon % i !== 0) {
smallestCommon += max;
doneCalc = 0;
break;
}
else {
doneCalc = 1;
}
}
}
return smallestCommon;
}
Here is another nonrecursive for-loop solution
function smallestCommons(arr) {
var biggestNum = arr[0];
var smallestNum = arr[1];
var thirdNum;
//make sure biggestNum is always the largest
if (biggestNum < smallestNum) {
thirdNum = biggestNum;
biggestNum = smallestNum;
smallestNum = thirdNum;
}
var arrNum = [];
var count = 0;
var y = biggestNum;
// making array with all the numbers fom smallest to biggest
for (var i = smallestNum; i <= biggestNum; i += 1) {
arrNum.push(i);
}
for (var z = 0; z <= arrNum.length; z += 1) {
//noprotect
for (y; y < 10000000; y += 1) {
if (y % arrNum[z] === 0) {
count += 1;
break;
}
else if (count === arrNum.length) {
console.log(y);
return y;
}
else {
count = 0;
z = 0;
}
}
}
}
smallestCommons([23, 18]);
function smallestCommons(arr) {
var sortedArr = arr.sort(); // sort array first
var tempArr = []; // create an empty array to store the array range
var a = sortedArr[0];
var b = sortedArr[1];
for(var i = a; i <= b; i++){
tempArr.push(i);
}
// find the lcm of 2 nums using the Euclid's algorithm
function gcd(a, b){
while (b){
var temp = b;
b = a % b;
a = temp;
}
return a;
}
function lcm(a, b){
return Math.abs((a * b) / gcd(a, b));
}
var lcmRange = tempArr.reduce(lcm);
return lcmRange;
}
function smallestCommons(arr) {
let smallest, biggest, min;
arr.reduce(function (a, b) {
biggest = Math.max(a, b);
});
const max = biggest;
arr.reduce(function (a, b) {
smallest = Math.min(a, b);
min = smallest;
});
check: while (true) {
biggest += max;
for (min = smallest; min < max; min++) {
if (biggest % min != 0) {
continue check;
}
if (min == (max - 1) && biggest % min == 0) {
console.warn('found one');
return biggest;
}
}
}
}
function smallestCommons(arr) {
let min = Math.min(arr[0], arr[1]);
let max = Math.max(arr[0], arr[1]);
let scm = max;
//calc lcm of two numbers:a,b;
const calcLcm = function(a, b) {
let minValue = Math.min(a, b);
let maxValue = Math.max(a, b);
let lcm = maxValue;
while (lcm % minValue !== 0) {
lcm += maxValue;
}
return lcm;
}
//calc scm in range of arr;
for (let i = max; i >= min; i--) {
scm = calcLcm(scm, i);
}
console.log(scm);
return scm;
}
smallestCommons([1, 13]);
this is another very simple way and have low complexity.
function smallestCommons(arr) {
let smallestNum = arr[0] < arr[1] ? arr[0] : arr[1];
let greatestNum = arr[0] > arr[1] ? arr[0] : arr[1];
let initalsArr = [];
for(let i = smallestNum; i <= greatestNum; i++){
initalsArr.push(i);
}
let notFoundFlag = true;
let gNMltpl = 0;
let filteredArrLen;
while(notFoundFlag){
gNMltpl += greatestNum;
filteredArrLen = initalsArr.filter((num)=>{
return (gNMltpl / num) === Math.floor((gNMltpl / num))
}).length;
if(initalsArr.length == filteredArrLen){
notFoundFlag = false;
}
}
return gNMltpl;
}
My solution using es6 feature is
Lcm of given numbers
const gcd = (a, b) => (!b ? a : gcd(b, a % b));
const lcm = (a, b) => a * (b / gcd(a, b));
const getLcm = (arr) => {
const numbers = arr.sort((a, b) => parseInt(a) - parseInt(b));
let result = parseInt(numbers[0]);
for (let i = 1; i < numbers.length; i++) {
result = lcm(parseInt(result), parseInt(numbers[i + 1]));
}
return result;
};
Hcf of given numbers
const getHcf = (arr) => {
const numbers = arr.sort((a, b) => parseInt(a) - parseInt(b));
let result = parseInt(numbers[0]);
for (let i = 1; i < numbers.length; i++) {
result = gcd(parseInt(numbers[i]), parseInt(result));
}
return result;
};
Call like this
console.log(getLcm([20, 15, 10, 40])). Answer 120
console.log(getHcf([2, 4, 6, 8, 16])). Answer 2
I also found myself working on this challenge on my freeCodeCamp JavaScript Certification. This is what I have been able to come up with:
function smallestCommons(arr) {
let newArr = [];
// create a new array from arr [min, min + 1,......., max - 1, max]
for (let i = Math.min(...arr); i <= Math.max(...arr); i++){
newArr.push(i);
}
// let the max of newArr be the smallestCommonMultiple initially
let largest = Math.max(...newArr);
let smallestCommonMultiple = largest;
// If the supposedly smallestCommonMultiple fail on any of elements in
//newArr add the max element until we find the smallestCommonMultiple.
while (newArr.some(element => smallestCommonMultiple % element !== 0)){
smallestCommonMultiple += largest;
}
return smallestCommonMultiple;
}
console.log(smallestCommons([23, 18]));
i think it will work.
var a = [2, 6];
function getTotalX(a) {
var num = 1e15;
var i;
var arr = [];
for (i = 1; i <=num ; i++){
arr.push(i);
}
for (i = 0; i < a.length; i++){
var filterArr = arr.filter((val, ind, arr) => (val % a[i] === 0));
}
console.log(filterArr[0]); // will return 6
}
I've made a similar function in typescript that does the same task but only without recursion...
function findLowestCommonMultipleBetween(start: number, end: number): number {
let numbers: number[] = [];
for (let i = start; i <= end; i++) {
numbers.push(i);
}
for (let i = 1; true; i++) {
let divisor = end * i;
if (numbers.every((number) => divisor % number == 0)) {
return divisor;
}
}
}
function smallestCommons(arr) {
let min = Math.min(...arr);
let max = Math.max(...arr);
let rangArr = [];
for(let i = min; i <= max; i++) rangArr.push(i);
let smallestCommon = max;
while(!rangArr.every(e => smallestCommon % e === 0)){
smallestCommon += max;
}
return smallestCommon;
}
console.log(smallestCommons([1, 13]));
function smallestCommons(arr) {
arr = arr.sort((a, b) => a - b)
let range = []
for (let i = arr[0]; i <= arr[1]; i++) {
range.push(i)
}
for(let i = arr[1]; ; i++){
if(range.every((num => i % num == 0))){
return i
}
}
}
function smallestCommons(arr) {
// Kind of a brute force method, It's not fancy but it's very simple and easy to read :P
// make an array with all the numbers in the range.
let numbersArr = [];
for (let i = Math.min(...arr); i <= Math.max(...arr); i++) {
numbersArr.push(i);
}
// keep multiplying the biggest number until it's divisible by all the numbers in the numbersArr array.
let scm = Math.max(...arr);
while (true) {
if (numbersArr.every(num => scm % num === 0)) {
return scm;
} else {
scm += Math.max(...arr);
}
}
}
smallestCommons([2, 10]); // returns 2520.
smallestCommons([1, 13]); // returns 360360.
smallestCommons([23, 18]); // returns 6056820.
function leastCommonMultiple(arr) {
// Setup
const [min, max] = arr.sort((a, b) => a - b);
// Largest possible value for LCM
let upperBound = 1;
for (let i = min; i <= max; i++) {
upperBound *= i;
}
// Test all multiples of 'max'
for (let multiple = max; multiple <= upperBound; multiple += max) {
// Check if every value in range divides 'multiple'
let divisorCount = 0;
for (let i = min; i <= max; i++) {
// Count divisors
if (multiple % i === 0) {
divisorCount += 1;
}
}
if (divisorCount === max - min + 1) {
return multiple;
}
}
}
//for a test
leastCommonMultiple([1, 5]);

Categories