create unique value and push to array in javascript - javascript

I need to create a array with unique values. In here if the created value is include in that array, then need to create another value and again need to check that newly created value exists in that array, if again exists then need to do the same check.
Here is the code I have tried, if I execute this, I think infinite looping scene happening.
let arr = [];
for(let i=0; i<10;i++) {
let k = 1;
let pass = (Math.floor(Math.random() * (10 - 6 + 1)) + 6)+'a';
while(k > 0){
k++;
if(arr.indexOf(pass) > -1) {
pass = (Math.floor(Math.random() * (10 - 6 + 1)) + 6)+'a';
} else {
arr.push(pass);
break;
}
console.log(arr)
}
}
What was the mistake in this code?

Yep, you're correct. It's an infinite loop.
The problem is the line pass = (Math.floor(Math.random() * (10 - 6 + 1)) + 6)+'a';. This will only ever generate one of 5 values. pass will only ever be
6a
7a
8a
9a
10a
Beause your array is 10 elements long, but you're only filling it with 5 possible elements, you will never be able to fill it with all unique elements. So it will go into an infinite loop trying to generate unique elements but never finding unique elements.
You need to rewrite the calculation of pass to generate more than 5 unique elements. Try pass = (Math.floor(Math.random() * 10))+'a'; and go from there.

let arr = [(Math.floor(Math.random() * (10)))+'a'];
for(let i=0; i<=10;i++) {
let k = 0;
let pass = (Math.floor(Math.random() * (10)))+'a';
while(k < arr.length){
k++;
if(arr.indexOf(pass) > -1){
pass = (Math.floor(Math.random() * (10 - 6 + 1)) + 6)+'a';
}else {
arr.push(pass);
break;
}
}
}
console.log(arr)
variable k is always > 0 in your condition and it loops infinitely.
edit 1:
answer updated based on #Mathew answer

Related

simplify javascript array with loop syntax

I have a javascript array defined as below:
var hexgon = ['M',r*Math.cos(0/180*Math.PI),r*Math.sin(0/180*Math.PI)
,r*Math.cos(30/180*Math.PI),r*Math.sin(30/180*Math.PI)
,r*Math.cos(90/180*Math.PI),r*Math.sin(90/180*Math.PI)
,r*Math.cos(150/180*Math.PI),r*Math.sin(150/180*Math.PI)
,r*Math.cos(210/180*Math.PI),r*Math.sin(210/180*Math.PI)
,r*Math.cos(270/180*Math.PI),r*Math.sin(270/180*Math.PI),
,r*Math.cos(330/180*Math.PI),r*Math.sin(330/180*Math.PI),'Z']
How to use a loop to simplify this logic?
If you did not intend two commas in a row after the twelth element then this:
var hexgon = ['M', ...[0,30,90,150,210,270,330].flatMap(d => [r*Math.cos(d/180*Math.PI),r*Math.sin(d/180*Math.PI)]), 'Z']
If you can have a constant value as a step that gets added to Math.cos() and Math.sin() statements we might be able to do something.
Let's say we want to add 30 each time to the each array's element, we can do something like this: (Also noticed there are M and Z characters at the beginning and end of your array)
const newHexgon = new Array(16);
newHexgon[0] = 'M';
newHexgon[newHexgon.length - 1] = 'Z';
let counter = 0;
let step = 30;
for (let i = 1; i < newHexgon.length - 1; i += 2) {
newHexgon[i] = Math.cos(((counter * step) / 180) * Math.PI);
newHexgon[i + 1] = Math.sin(((counter * step) / 180) * Math.PI);
counter++;
}
console.log(newHexgon);
I created an array with a length of 16 and set the first and last elements to "M" and "Z" as in your array. Then I will loop every two elements at a time i += 2 and set the Math calculations and after finished in each iteration the counter gets added by one.

Picking Non-duplicate Random Numbers using JavaScript

How would I pick 5 random lottery numbers without having duplicate numbers? The code below is what I have so far and I just can't figure out where to insert the code to loop through to pick out duplicate numbers and reassign new numbers? I've tried adding if and else along with forEach function but it didn't work. This is the code I have so far. Thank you in advance.
let lotto = [];
for(let i = 0; i < 5; i++){
lotto[i] = Math.floor(Math.random() * 69) + 1;
}
const sorting = lotto.sort((a,b) => a - b);
console.log(sorting);
Two solutions:
Create a list of your numbers, then pick (and remove) 5 from them.
Create a loop that keeps generating numbers until it has 5 unique ones.
Your attempt can be adapted for solution 2:
let lotto = [];
while(lotto.length < 5) {
console.log('Got', lotto.length, 'numbers!');
// Changed 69 to 5 to "force" clashes (well, make it very likely)
const num = Math.floor(Math.random() * 5) + 1;
if (!lotto.includes(num)) lotto.push(num);
}
const sorting = lotto.sort((a, b) => a - b);
console.log(sorting);
Considering the process will run at leats one time, the best solution is to use a do while loop and verify if this number already exist in the list.
const lotto = [];
do {
const random = Math.floor(Math.random() * 69) + 1;
if(!lotto.includes(random)) lotto.push(random);
} while(lotto.length < 5);
const sorting = lotto.sort((a, b) => a - b);
console.log(sorting);

How to generate a unique no between1 and 10 but not equal to the current no or current value?

I want to generate a random number between 1 and 10 but it should not be equal to the current no or current value?
I looked at this below answer but having difficulty in making it as module since current no has to be retrieved from different file. I pretty much want something like this, but not exactly (if yo get what I mean).
Simple - just use a function which takes the current number, and generate a random number from 1-10 and, if it's equal to the current number, recalculate and re-check:
function newRandomNumber(currentNumber) {
var random = Math.floor(Math.random() * 10) + 1;
while (random == currentNumber) {
random = Math.floor(Math.random() * 10) + 1;
}
return random;
}
I have the below solution:
let previousValue = Math.floor(Math.random() * 10) + 1
for(let i = 0; i < 20 ; ++i) {
previousValue = (previousValue + Math.floor(Math.random() * 9)) % 10 + 1
console.log(new Date(), previousValue)
}
As you can see you create a previousValue to initiate the process. To generate another value between 1 and 10 but different than the previous one the solution is to generate a value between 0 and 9 and add it to the previous value. Using modulo operator you end up with a result in the correct range and different from the previous one.

How to properly create JQuery inArray if statement?

I am generating a list of random numbers. Each random number is added to an array, but I want to check that the same number isnt entered twice. I am having a lot of trouble trying to get the if statement to work with this and am not sure what I have done wrong.
I have created:
//INITIALISE VARS, ARRAYS
var uniquearr = [];
i = 0;
while (i < 30){
var min = 0;
var max = 29;
var random = Math.floor(Math.random() * (max - min + 1)) + min;
//SEARCH UNIQUE ARRAY FOR EXISTING
if (jQuery.inArray(random, uniquearr) > -1){
//ADD NUMBER TO UNIQUE ARRAY
uniquearr.push(random);
//*DO SOMETHING*
} //END IF
i++;
} //END WHILE
But the if statement never triggers. Can anyone point me in the right direction?
You need to test whether the random number does not exist in the array; only then should it be added to the array.
Also another problem with the logic was, you were not adding the 30 unique numbers always as the i variable was incremented outside the if condition. Here you do not have to use a different loop variable since you can check whether the destination array is of desired size
//INITIALISE VARS, ARRAYS
var uniquearr = [], min = 0, max = 29;
//SEARCH UNIQUE ARRAY FOR EXISTING
while (uniquearr.length < 30){
var random = Math.floor(Math.random() * (max - min + 1)) + min;
if (jQuery.inArray(random, uniquearr) == -1){
uniquearr.push(random);
}//END IF
}//END WHILE
console.log('uniquearr', uniquearr)
That's because your if statement always is false, your array is empty and as result $.inArray always returns -1, you should check whether the returned value is -1 or not.
while (uniquearr.length < 30) { // uniquearr.length !== 30
var min = 0,
max = 29,
random = Math.floor(Math.random() * (max - min + 1)) + min;
//SEARCH UNIQUE ARRAY FOR EXISTENCE
if (jQuery.inArray(random, uniquearr) === -1) {
//ADD NUMBER TO UNIQUE ARRAY
uniquearr.push(random);
}
}
http://jsfiddle.net/zzL7v/

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