Getting the sum of array - javascript

I have an array of number
[350000, 350000, 350000]
I have the following code:
function getNPV(rate, periods, Cashflow) {
var npv = 0;
for (var i = 0; i < Cashflow.length; i++) {
npv += Cashflow[i] / Math.pow(1 + rate, periods);
}
return npv;
}
Here, cashflow is our array, rate = 6% and period = 91days.
When I take :
npv = Cashflow[i] / Math.pow(1 + rate, periods);
The output is [348328,346664,344952] when 6% discount rate is applied to 350000 each time.
I am trying to take the sum of [348328,346664,344952] which is $1,039,944
But, it is giving me $1034856 as the result.
Trying the console, it's actually taking the sum of the 3rd value 3 times instead. [344952+344952+344952] for some reason.
Can someone please tell me how to fix this error. Any help is appreciated. Thank you.

As I refer to your spreadsheet, you need an array for period not cashflow.
Pass periods and cashflow like:
var periods = [30, 60, 91];
var cashflow = 350000;
getNPV(rate, periods, cashflow);
Your cash flow is same, so no need an array (You may still have an array if you want to vary cashflow)
And use it in the loop:
function getNPV(rate, periods, Cashflow) {
var npv = rate;
for (var i = 0; i < periods.length; i++) {
npv += Cashflow / Math.pow(1 + rate, periods[i]);
}
return npv;
}

You can use returnSum to get the sum of the array
function returnSum(arr) {
function sum(a, b) {
return a + b;
}
return arr.reduce(sum, 0);
}
let array = [348328,346664,344952]
returnSum(array); //result 1039944

Related

How do i create a function, which takes one parameter - a number, and returns the sum of numbers from 1 -> number - without creating an infinite loop?

How do i create a function, which takes one parameter - a number, and returns the sum of numbers from 1 -> number - without creating an infinite loop?
Example:
function(100)
= 5050
Ive come as far as creating a finite for loop as so:
let sum = 0
for (let i = 1; i <= 100; i++) {
sum = sum + i;
//thanks in advance
Well, it looks like you've got the basic premise sussed out for 1 to 100 - you're cycling through to the value and summing up. To put it into a bit of a nicer format:
const n = 100;
console.log(GetSumTo(n))
function GetSumTo(x) {
var sum = 0;
for (var i = 1; i <= x; i++) {
sum = sum + i;
}
return sum;
}
Another option would be do it recursively:
const n = 100;
console.log(RecursiveSum(n, 0));
function RecursiveSum(val, sum) {
if (val > 1) {
sum = val + RecursiveSum(val - 1, sum);
}
else {
sum = val;
}
return sum;
}
However, these can be time consuming when dealing with large values. Using a fancy bit of maths (explained here better than I can explain it: https://math.stackexchange.com/questions/1100897/sum-of-consecutive-numbers), we can find that the sum of consecutive numbers can be calculated with an easier formula: (n(n + 1))/2
Meaning we can just write a function to do that and save execution time:
const n = 100;
console.log(QuickSum(n));
function QuickSum(n) {
var sum = n + 1;
sum = sum * n;
sum = sum / 2; //You could shrink the calculation to sum = (n * (n + 1)) / 2 I just did it over a few lines for readability
return sum;
};
None of these options result in an infinite loop.

Javascript adding multiple arrays in a loop

I am trying to add multiple arrays in javascript.
Here are my arrays I have made, and are working.
function getAmountSpent(){
var amountSpent = ((Math.random() * 500) + 1);
return amountSpent.toFixed(2)
}
function getGift(){
var gift = ((Math.random()* 50) + 1);
return gift.toFixed(2)
}
var names = ["Jeremy","Arun","Alisa","Rohan","Dana"];
var spent = [];
for (let i = 0; i < 5; i++) {
spent.push(getAmountSpent());
}
var gifts = [];
for (let i = 0; i<5; i++) {
gifts.push(getGift());
}
What I need help with is adding these arrays in a new function. I have began writing the code, and I am not sure what is wrong.
var totals =[];
for (let i=0; i<5; i++) {
totals.push(getSumTotals())
}
function getSumTotals(a){
totals= spent+(spent * gifts);
return totals.toFixed(2)
}
From what you can see, I am trying to add up the totals much like this:
totals[0] = spent[0] + (spent[0] * gifts[0]);
totals[1] = spent[1] + (spent[1] * gifts[1]);
totals[2] = spent[2] + (spent[2] * gifts[2]);
totals[3] = spent[3] + (spent[3] * gifts[3]);
totals[4] = spent[4] + (spent[4] * gifts[4]);
if it helps, the professor added guided instructions for function getSumTotals(a) stating:
This function will return the sum of the elements in array a.
You will be passing the array that holds your totals to
the parameter a. Be sure to treat the values in a as numbers.
I am not sure if this helps but here is the output to my document.
Current Total should equal (spent) + (spent * gifts). For instance, for Jeremy in this example, current total should equal:
$36.55 + ($36.55*0.0626) = $38.83. Since there are many variables involved, I am not 100% sure what I should write for function getSumTotals(a)
The parameter "a" is a placeholder because I am not sure how many parameter values I need, and the proper format I need to use.
As for the code...
You're both
not passing an index to getSumTotals
not using this parameter within getSumTotals to access your spent and gifts arrays
var totals =[];
for (let i=0; i<5; i++) {
totals.push(getSumTotals(i)) // you were missing i
}
function getSumTotals(idx) { // I took liberties to rename this
totals = spent[idx] + (spent[idx] * gifts[idx]);
return totals.toFixed(2);
}
Now for the Math...
All that said, this math of spent[i] + spent[i] * gifts[i] doesn't make much sense either. Was this specified in the problem?
you may use like this
defined gifts
gifts=[45,43,32];
defined spends
spends=[43,32,21];
this is the getSumTotal funtion
getSumTotal=(x)=>(x.a+x.b)
this is where added
totals=gifts.map((d1,i)=>{
return fu({a:gifts[i],b:spends[i]})
})
I understand this is your assignment, however - if the idea is to both generate arrays, and then add them together, it is a redundant step. Just use the name array to iterate once and do all your calculations within that single loop.
Here, I had some fun and took some liberties, but hopefully you see why multiple arrays are redundant.
function getSumTotals() {
const getAmountSpent = () => Math.random() * 500 + 1;
const getGift = () => Math.random() * 50 + 1;
const names = ["Jeremy", "Arun", "Alisa", "Rohan", "Dana"];
let totals = []
names.forEach((name, i) => {
let spent = getAmountSpent()
let gifts = getGift()
let $$$ = (spent + spent * gifts).toFixed(2);
totals[i] = $$$
console.log(`${name} cost me $${$$$}${'!'.repeat(($$$/1000) | 1)}`)
});
return totals;
}
getSumTotals()
Note, that toString returns a type of "String", but not "Number".
When you try to sum a number with string, you get a concatenated string "1" + 2 = "12"
To turn a string into Number, you must use a Number("str") function, or just a bunary + before the string:
console.log( "1" + 2 );
console.log( Number("1") + 2 );
console.log( +"1" + 2 );
Also, you use the same loop 3 times, but can use just one loop instead, and call all functions inside the one loop. And use your array.length instead of fixed number 5:
let names = ["Jeremy", "Arun", "Alisa", "Rohan", "Dana"];
let spent = [];
let gifts = [];
let totals = [];
for (let i = 0; i < names.length; i++) {
spent.push( getAmountSpent() );
gifts.push( getGift() );
totals.push( getSumTotals(i) );
}
console.log( totals );
function getAmountSpent() {
return rand(1, 500, 2);
}
function getGift() {
return rand(1, 50, 2);
}
function getSumTotals(i) {
return +( spent[i] * ( 1 + gifts[i] ) ).toFixed(2);
}
function rand(from, to, fixed = 0){
return +(Math.random()*( to - from ) + from).toFixed(fixed);
}
P.s. Math.random() returns a number between 0 (included) and 1 (not included). If you need a random number between (example) 20 and 100, Math.random()*(100-20) will give a number between 0 and 80. After adding +20 to the result, you get a number from 20 to 100. That's what does this formula Math.random()*( to - from ) + from
P.P.s. Another way, to get the same thing:
var names = ["Jeremy", "Arun", "Alisa", "Rohan", "Dana"].reduce( (prev, elem) => {
let spent = rand(1, 500, 2);
let gift = rand(1, 50, 2);
prev[elem] = new UserData( spent, gift );
return prev;
}, {});
console.log( "Jeremy spent: " + names.Jeremy.spent );
console.log( names );
function rand(from, to, fixed = 0){
return +(Math.random()*( to - from ) + from).toFixed(fixed);
}
function UserData(spent, gift){
this.spent = spent;
this.gift = gift;
this.total = +(spent * ( 1 + gift )).toFixed(2);
}
/* Google → Array reduce, Constructor functions */
function getAmountSpent(){
let amountSpent = ((Math.random() * 500) + 1);
return Number(amountSpent.toFixed(2))
}
function getGift(){
let gift = ((Math.random()* 50) + 1);
return Number(gift.toFixed(2))
}
let names = ["Jeremy","Arun","Alisa","Rohan","Dana"];
let spent = [];
let gifts = [];
let totals =[];
for (let i = 0; i < names.length; i++) {
spent.push(getAmountSpent());
gifts.push(getGift());
totals[i] = (spent[i]+(spent[i] * gifts[i])).toFixed(2);
totals[i] = parseFloat(totals[i])
}
Hi there
I don't think you need a function to add the totals. you just need to loop through and assign totals[i] to spent[i] + (spent[i] * gifts[i]).
then you can use the parseFloat and toFixed function to change the string to a number. remember toFixed() function turns numbers to string. so you need to use the parseFloat to change it to number again as shown in the code above. or you can come up with an easy way of changing it to number. I hope this helps!

How to generated N numbers in array that sum of these numbers is equal to 0

I have a code like this:
function myArr(N){
let arr = [];
function randomNumber(min,max) {
if (min > max) {
let vMin = min;
min = parseInt(max,10);
max = parseInt(vMin,10);
}
return Math.floor(Math.random()*(max-min+1)+min);
}
for(let i = 0; i < N; i++) {
arr.push(randomNumber(100,-100));
}
return arr;
}
This function generates an array with N numbers. But I want that the sum of these generated numbers will be equal to 0. How to make it? I was thinking about conditional 'if' but I don't exactly know, how to use it in this case ... Maybe some of you know, how to do this? Thanks for any tips!
There are many ways to generate an array of randomly-generated values that add up to zero, but they all have different implications for the distribution of values.
For example, one simple approach is to first generate the values and compute their average, and then subtract that average from each value. The consequence of this is that the values may end up outside the range you originally wanted; for example, if you randomly generate [100, 100, 100, -100], then the average is 50, so you'd end up with [50, 50, 50, -150]. You can compensate for that by starting out with a narrower range than you really need; but then that means that values in or near that narrower range will be much more likely to appear than values near the end of your full range.
Another simple approach is to generate only n/2 values, and for each value that you generate, to include both that value and its arithmetic inverse (e.g., if you generate 37, then your result will include both 37 and -37). You can then randomly shuffle the result; so, for example, if you randomly generate [17, -84, 12], then your final array might be [-12, 17, -84, -17, 84, 12].
. . . all of which is to say that you need to figure out your precise requirements. Randomness is complicated!
While generating numbers you have to make sure that the numbers stay close to zero, then you generate N - 1 numbers and calculate the last one:
const arr = [];
let sum = 0;
for(let i = 0; i < N - 2; i++) {
let number;
if(sum >= 100) {
number = randomNumber(100 - sum, -100);
} else if(sum <= -100) {
number = randomNumber(100, -100 - sum);
} else {
number = randomNumber(100, -100);
}
sum += number;
arr.push(number);
}
arr.push(Math.floor(-sum / 2), Math ceil(-sum / 2));
Try it
(Won't work well for N < 4)
Here's another way. Start with zero and split a random array element N-1 times:
function myArr(N){
let arr = [0];
function randomNumber(min,max) {
if (min > max) {
let vMin = min;
min = parseInt(max,10);
max = parseInt(vMin,10);
}
return Math.floor(Math.random()*(max-min+1)+min);
}
function split(n){
let low = Math.max(-100, n - 100);
let high = Math.min(100, n + 100);
let r = randomNumber(low, high);
return [r, n - r]
}
for(let i = 0; i < N-1; i++) {
let idx = ~~(Math.random() * arr.length);
let newNums = split(arr[idx]);
arr[idx] = newNums[0];
arr.push(newNums[1]);
}
return arr;
}
console.log(myArr(5));
This is my solution, basically you do a for loop and start adding elements.
Whenever you add an element, just add the same element * -1
You will end up with an array of elements with sum 0.
function arrayOfSumZero(N) {
let sum = 0;
let i = N % 2 === 0 ? 0 : 1;
let output = [];
for (i; i < N; i++) {
if (output.length < N) {
sum += i;
output.push(i);
}
if (sum > 0) {
sum += i * -1;
output.push(i * -1);
}
}
return output;
}

Comparing current and next element of array and returning time difference

This is my array. Its length is about 9000. This is what a small bit of it looks like:
foreach_arr = ["21:07:01.535", "21:07:01.535", "21:07:26.113"]
There are a few occurences where the times diff is greater than a minute, and that is when I want to grab those times. And later use those times to get certain indices from another array. i.e "array"
I'm also using moment.js for time parsing.
Expected result: array = [8127, 9375, 13166, 14182]
Actual result: array = [8127, 13166]
Can't seem to find the issue here, I am getting 2 results when im supposed to be getting 4.
If the whole array is needed for troubleshooting, ill add it if I can.
var xx = foreach_arr.length - 1;
for(var z = 0; z < xx; z++) {
var current_row = foreach_arr[z];
var next_row = foreach_arr[z + 1];
var msElapsedTime = moment(next_row,"HH:mm:ss.SSS").diff(moment(current_row, "HH:mm:ss.SSS")) / 1000;
if(msElapsedTime > 60) {
attempt_indices.push(foreach_arr[z]);
}
}
for(var x = 0; x < attempt_indices.length; x++) {
array.push(newdata.indexOf(attempt_indices[x]));
}
Since the OP doesn't really need my code anymore, I'm posting it here to remove the downvote as much as anything else :)
const foreach_arr = ["21:07:01.535", "21:07:01.535", "21:07:26.113", '22:01:01.000'];
let processedForeach_arr = [];
let gtOneMinuteDiff = [];
foreach_arr.forEach((elem1, index1) => {
// elem1.split(':') turns foreach_arr[0] into ['21', '07', '01.535']
const splitElementArray = elem1.split(':');
let timeInMs = 0;
// this changes ['21', '07', '01.535'] into [75600000, 420000, 1535]
splitElementArray.forEach((elem2, index2) => {
if (index2 === 0) { // elem2 is hours. 3.6M ms per hour.
timeInMs += parseFloat(elem2) * 60 * 60 * 1000;
} else if (index2 === 1) { // elem2 is minutes. 60K ms per minute.
timeInMs += parseFloat(elem2) * 60 * 1000;
} else if (index2 === 2) { // elem2 is seconds. 1K ms per second.
timeInMs += parseFloat(elem2) * 1000;
} else {
throw `Expected array element formatted like HH:MM:SS.ms. Error on
element ${elem1}.`;
}
});
processedForeach_arr.push(timeInMs);
let timeDiff = processedForeach_arr[index1 - 1] - processedForeach_arr[index1];
if (Math.abs(timeDiff) > 60000) {
gtOneMinuteDiff.push(timeDiff);
}
});
To get the difference in milliseconds between foreach_arr[n] and foreach_arr[n+1], this code will
split each element of foreach_arr into 3 strings (hours, minutes, and seconds + milliseconds)
run parseFloat on each of those values to convert them to a number
convert all numbers to milliseconds and add them together
compare each consecutive value and return the difference.
Ok, I got this far and my son needs me. I'll finish out the code asap but you might beat me to it, hopefully the instructions above help.
turns out my code wasn't wrong. Just my idea of the whole proccess.
array = [8127, 13166]
is what I initialy get. With this, I use indexOf on my other array to eventually get my array as expected:
var another_test_arr = [];
for(var v = 0; v < array.length ; v++) {
var find = foreach_arr.indexOf(attempt_indices[v]);
another_test_arr.push(array[v], newdata.indexOf(foreach_arr[find + 1]));
}
Result: array = [8127, 9375, 13166, 14182]

Generating unique random numbers (integers) between 0 and 'x'

I need to generate a set of unique (no duplicate) integers, and between 0 and a given number.
That is:
var limit = 10;
var amount = 3;
How can I use Javascript to generate 3 unique numbers between 1 and 10?
Use the basic Math methods:
Math.random() returns a random number between 0 and 1 (including 0, excluding 1).
Multiply this number by the highest desired number (e.g. 10)
Round this number downward to its nearest integer
Math.floor(Math.random()*10) + 1
Example:
//Example, including customisable intervals [lower_bound, upper_bound)
var limit = 10,
amount = 3,
lower_bound = 1,
upper_bound = 10,
unique_random_numbers = [];
if (amount > limit) limit = amount; //Infinite loop if you want more unique
//Natural numbers than exist in a
// given range
while (unique_random_numbers.length < limit) {
var random_number = Math.floor(Math.random()*(upper_bound - lower_bound) + lower_bound);
if (unique_random_numbers.indexOf(random_number) == -1) {
// Yay! new random number
unique_random_numbers.push( random_number );
}
}
// unique_random_numbers is an array containing 3 unique numbers in the given range
Math.floor(Math.random() * (limit+1))
Math.random() generates a floating point number between 0 and 1, Math.floor() rounds it down to an integer.
By multiplying it by a number, you effectively make the range 0..number-1. If you wish to generate it in range from num1 to num2, do:
Math.floor(Math.random() * (num2-num1 + 1) + num1)
To generate more numbers, just use a for loop and put results into an array or write them into the document directly.
function generateRange(pCount, pMin, pMax) {
min = pMin < pMax ? pMin : pMax;
max = pMax > pMin ? pMax : pMin;
var resultArr = [], randNumber;
while ( pCount > 0) {
randNumber = Math.round(min + Math.random() * (max - min));
if (resultArr.indexOf(randNumber) == -1) {
resultArr.push(randNumber);
pCount--;
}
}
return resultArr;
}
Depending on range needed the method of returning the integer can be changed to: ceil (a,b], round [a,b], floor [a,b), for (a,b) is matter of adding 1 to min with floor.
Math.floor(Math.random()*limit)+1
for(i = 0;i <amount; i++)
{
var randomnumber=Math.floor(Math.random()*limit)+1
document.write(randomnumber)
}
Here’s another algorithm for ensuring the numbers are unique:
generate an array of all the numbers from 0 to x
shuffle the array so the elements are in random order
pick the first n
Compared to the method of generating random numbers until you get a unique one, this method uses more memory, but it has a more stable running time – the results are guaranteed to be found in finite time. This method works better if the upper limit is relatively low or if the amount to take is relatively high.
My answer uses the Lodash library for simplicity, but you could also implement the algorithm described above without that library.
// assuming _ is the Lodash library
// generates `amount` numbers from 0 to `upperLimit` inclusive
function uniqueRandomInts(upperLimit, amount) {
var possibleNumbers = _.range(upperLimit + 1);
var shuffled = _.shuffle(possibleNumbers);
return shuffled.slice(0, amount);
}
Something like this
var limit = 10;
var amount = 3;
var nums = new Array();
for(int i = 0; i < amount; i++)
{
var add = true;
var n = Math.round(Math.random()*limit + 1;
for(int j = 0; j < limit.length; j++)
{
if(nums[j] == n)
{
add = false;
}
}
if(add)
{
nums.push(n)
}
else
{
i--;
}
}
var randomNums = function(amount, limit) {
var result = [],
memo = {};
while(result.length < amount) {
var num = Math.floor((Math.random() * limit) + 1);
if(!memo[num]) { memo[num] = num; result.push(num); };
}
return result; }
This seems to work, and its constant lookup for duplicates.
These answers either don't give unique values, or are so long (one even adding an external library to do such a simple task).
1. generate a random number.
2. if we have this random already then goto 1, else keep it.
3. if we don't have desired quantity of randoms, then goto 1.
function uniqueRandoms(qty, min, max){
var rnd, arr=[];
do { do { rnd=Math.floor(Math.random()*max)+min }
while(arr.includes(rnd))
arr.push(rnd);
} while(arr.length<qty)
return arr;
}
//generate 5 unique numbers between 1 and 10
console.log( uniqueRandoms(5, 1, 10) );
...and a compressed version of the same function:
function uniqueRandoms(qty,min,max){var a=[];do{do{r=Math.floor(Math.random()*max)+min}while(a.includes(r));a.push(r)}while(a.length<qty);return a}
/**
* Generates an array with numbers between
* min and max randomly positioned.
*/
function genArr(min, max, numOfSwaps){
var size = (max-min) + 1;
numOfSwaps = numOfSwaps || size;
var arr = Array.apply(null, Array(size));
for(var i = 0, j = min; i < size & j <= max; i++, j++) {
arr[i] = j;
}
for(var i = 0; i < numOfSwaps; i++) {
var idx1 = Math.round(Math.random() * (size - 1));
var idx2 = Math.round(Math.random() * (size - 1));
var temp = arr[idx1];
arr[idx1] = arr[idx2];
arr[idx2] = temp;
}
return arr;
}
/* generating the array and using it to get 3 uniques numbers */
var arr = genArr(1, 10);
for(var i = 0; i < 3; i++) {
console.log(arr.pop());
}
I think, this is the most human approach (with using break from while loop), I explained it's mechanism in comments.
function generateRandomUniqueNumbersArray (limit) {
//we need to store these numbers somewhere
const array = new Array();
//how many times we added a valid number (for if statement later)
let counter = 0;
//we will be generating random numbers until we are satisfied
while (true) {
//create that number
const newRandomNumber = Math.floor(Math.random() * limit);
//if we do not have this number in our array, we will add it
if (!array.includes(newRandomNumber)) {
array.push(newRandomNumber);
counter++;
}
//if we have enought of numbers, we do not need to generate them anymore
if (counter >= limit) {
break;
}
}
//now hand over this stuff
return array;
}
You can of course add different limit (your amount) to the last 'if' statement, if you need less numbers, but be sure, that it is less or equal to the limit of numbers itself - otherwise it will be infinite loop.
Just as another possible solution based on ES6 Set ("arr. that can contain unique values only").
Examples of usage:
// Get 4 unique rnd. numbers: from 0 until 4 (inclusive):
getUniqueNumbersInRange(4, 0, 5) //-> [5, 0, 4, 1];
// Get 2 unique rnd. numbers: from -1 until 2 (inclusive):
getUniqueNumbersInRange(2, -1, 2) //-> [1, -1];
// Get 0 unique rnd. numbers (empty result): from -1 until 2 (inclusive):
getUniqueNumbersInRange(0, -1, 2) //-> [];
// Get 7 unique rnd. numbers: from 1 until 7 (inclusive):
getUniqueNumbersInRange(7, 1, 7) //-> [ 3, 1, 6, 2, 7, 5, 4];
The implementation:
function getUniqueNumbersInRange(uniqueNumbersCount, fromInclusive, untilInclusive) {
// 0/3. Check inputs.
if (0 > uniqueNumbersCount) throw new Error('The number of unique numbers cannot be negative.');
if (fromInclusive > untilInclusive) throw new Error('"From" bound "' + fromInclusive
+ '" cannot be greater than "until" bound "' + untilInclusive + '".');
const rangeLength = untilInclusive - fromInclusive + 1;
if (uniqueNumbersCount > rangeLength) throw new Error('The length of the range is ' + rangeLength + '=['
+ fromInclusive + '…' + untilInclusive + '] that is smaller than '
+ uniqueNumbersCount + ' (specified count of result numbers).');
if (uniqueNumbersCount === 0) return [];
// 1/3. Create a new "Set" – object that stores unique values of any type, whether primitive values or object references.
// MDN - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
// Support: Google Chrome 38+(2014.10), Firefox 13+, IE 11+
const uniqueDigits = new Set();
// 2/3. Fill with random numbers.
while (uniqueNumbersCount > uniqueDigits.size) {
// Generate and add an random integer in specified range.
const nextRngNmb = Math.floor(Math.random() * rangeLength) + fromInclusive;
uniqueDigits.add(nextRngNmb);
}
// 3/3. Convert "Set" with unique numbers into an array with "Array.from()".
// MDN – https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
// Support: Google Chrome 45+ (2015.09+), Firefox 32+, not IE
const resArray = Array.from(uniqueDigits);
return resArray;
}
The benefits of the current implementation:
Have a basic check of input arguments – you will not get an unexpected output when the range is too small, etc.
Support the negative range (not only from 0), e. g. randoms from -1000 to 500, etc.
Expected behavior: the current most popular answer will extend the range (upper bound) on its own if input bounds are too small. An example: get 10000 unique numbers with a specified range from 0 until 10 need to throw an error due to too small range (10-0+1=11 possible unique numbers only). But the current top answer will hiddenly extend the range until 10000.
I wrote this C# code a few years back, derived from a Wikipedia-documented algorithm, which I forget now (feel free to comment...). Uniqueness is guaranteed for the lifetime of the HashSet. Obviously, if you will be using a database, you could store the generated numbers there. Randomness was ok for my needs, but probably can be improved using a different RNG. Note: count must be <= max - min (duh!) and you can easily modify to generate ulongs.
private static readonly Random RndGen = new Random();
public static IEnumerable<int> UniqueRandomIntegers(int count, int min, int max)
{
var rv = new HashSet<int>();
for (var i = max - min - count + 1; i <= max - min; i++)
{
var r = (int)(RndGen.NextDouble() * i);
var v = rv.Contains(r) ? i : r;
rv.Add(v);
yield return v;
}
}
Randomized Array, Sliced
Similar to #rory-okane's answer, but without lodash.
Both Time Complexity and Space Complexity = O(n) where n=limit
Has a consistent runtime
Supports a positive or negative range of numbers
Theoretically, this should support a range from 0 to ±2^32 - 1
This limit is due to Javascript arrays only supporting 2^32 - 1 indexes as per the ECMAScript specification
I stopped testing it at 10^8 because my browser got weird around here and strangely only negative numbers to -10^7 - I got an Uncaught RangeError: Invalid array length error (shrug)
Bonus feature: Generate a randomized array of n length 0 to limit if you pass only one argument
let uniqueRandomNumbers = (limit, amount = limit) => {
let array = Array(Math.abs(limit));
for (let i = 0; i < array.length; i++) array[i] = i * Math.sign(limit);
let currentIndex = array.length;
let randomIndex;
while(currentIndex > 0) {
randomIndex = Math.floor(Math.random() * currentIndex--);
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
}
return array.slice(0, Math.abs(amount));
}
console.log(uniqueRandomNumbers(10, 3));
console.log(uniqueRandomNumbers(-10, 3));
//bonus feature:
console.log(uniqueRandomNumbers(10));
Credit:
I personally got here because I was trying to generate random arrays of n length. Other SO questions that helped me arrive at this answer for my own use case are below. Thank you everyone for your contributions, you made my life better today.
Most efficient way to create a zero filled JavaScript array?
How to randomize (shuffle) a JavaScript array?
Also the answer from #ashleedawg is where I started, but when I discovered the infinite loop issues I ended up at the sliced randomized array approach.
const getRandomNo = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
This function returns a random integer between the specified values. The value is no lower than min (or the next integer greater than min if min isn't an integer) and is less than (but not equal to) max.
Example
console.log(`Random no between 0 and 10 ${getRandomNo(0,10)}`)
Here's a simple, one-line solution:
var limit = 10;
var amount = 3;
randoSequence(1, limit).slice(0, amount);
It uses randojs.com to generate a randomly shuffled array of integers from 1 through 10 and then cuts off everything after the third integer. If you want to use this answer, toss this within the head tag of your HTML document:
<script src="https://randojs.com/1.0.0.js"></script>

Categories

Resources