How to get a random number without duplicate digits in JavaScript/jQuery? - javascript

Update: The number can be started with zero.
I want to have a function like
function getRandomNumber(n){
...
}
I hope it gets a number with n digits while none of the digits is repeated. For instance:
getRandomNumber(3) -> 152 is what I want.
getRandomNumber(1) -> 6 is what I want.
getRandomNumber(6) -> 021598 is what I want. It can start with zero.
getRandomNumber(5) -> 23156 is what I want.
getRandomNumber(3) -> 252 is not because it has two 2.
getRandomNumber(5) -> 23153 is not because it has two 3.
Any simple way to do this?

On each call, make an array of digits, and then repeatedly pick random values and remove them from said array:
function getRandomNumber(n){
const digits = Array.from({ length: 10 }, (_, i) => i);
const result = Array.from({ length: n }, () => {
const randIndex = Math.floor(Math.random() * digits.length);
const digit = digits[randIndex];
digits.splice(randIndex, 1);
return digit;
});
return Number(result.join(''));
}
Array.from({ length: 10 }, () => console.log(getRandomNumber(8)));

By keeping an array as an hash map, an efficient solution is as follows. However keep in mind that unless it's a string a number can not start with 0.
function getRandomNumber(n){
var a = [],
x = ~~(Math.random()*10),
r = 0;
while (n) {
a[x] === void 0 && (a[x] = true, r += x*Math.pow(10,n-1), --n);
x = ~~(Math.random()*10);
}
return r;
}
console.log(getRandomNumber(3));
console.log(getRandomNumber(4));
console.log(getRandomNumber(5));
console.log(getRandomNumber(6));
console.log(getRandomNumber(7));

Don't how to deal with javascript but if it can help you, here a line of scala doing the job
def obtainRestrictedRandomNumber(): Long = scala.util.Random.shuffle((0 to 9)).mkString("").toLong
What it does is simply generating all digits from 0 to 9 then randomize them, concatenate the Array Int elements into a string for finally casting it into a Long.

Related

How to make pseudo-random BigInt generator convert to string of particular length of characters?

Along the lines of How to get this PRNG to generate numbers within the range? , I am this far (parts is an array of 32 2-character "symbols"):
const parts = `mi
ma
mo
ne
nu
di
da
do
be
bu
ti
te
ta
to
tu
ki
ke
ka
ko
ku
si
sa
so
ze
zu
fi
fa
fo
ve
vu
xe
xu`.trim().split(/\n+/)
const fetch = (x, o) => {
if (x >= o) {
return x
} else {
const v = (x * x) % o
return (x <= (o / 2n)) ? v : o - v
}
}
const fetchLarge = (x) => fetch(x, 41223334444555556666667777777888888889999999997n)
// the last number can be anything.
const buildLarge = (x, o) => fetchLarge((fetchLarge(x) + o) % BigInt(Math.pow(32, 31)) ^ 2030507011013017019023n)
const createArray = (n, mod = 32n) => {
if (!n) return [0];
let arr = [];
while (n) {
arr.push(Number(n % mod));
n /= mod;
}
return arr;
}
const write = (i) => {
const x = buildLarge(i++, 272261127249452727280272961627319532734291n)
return createArray(x).map(x => parts[x]).join('')
}
let i = 1n
while (i < 10000) {
console.log(write(i))
}
I am generating results along the lines of:
kitekutefaxunetotuzezumatotamabukidimasoxumoxudofasositinu,6038940986212279582529645303138677298679151
sokiketufikefotekakidotetotesamizununetefokixefitetisovene,5431347628569519336817719657935192515363318
xudamituzesimixuxemixudakedatetutununekobuzexesozuxedinenu,5713969289948157459645315228321450728816863
dazenenemovudadikukatatakibekaxexemovubedivusidatafisasine,5082175912370834928186684152014555456835302
xufotidosokabunudomimibefisimakusimokedamomazexekofomokane,4925740069222414438181195472381794794580863
sodozekadakuzemaxetexukuzumisikitazufitizexekatetotuxusone,5182433137814021540565892366585827483507958
kikokasatudatidatufikizesadimatakakatudisibumofotuzutaze,1019165422643074024784461594259815846823503
dakikinetofonexesimavufafisaxefosafisikofotasanekovetevu,1279315636939618596561544978621478602915302
kinunebebuzukokemidatekobusofokikozukobedodakesisikunuki,659622269329577207976266617866288582888591
sozesifamoxebusitotesisasizekudasomitatavudidizukadimate,480714979099063166920265752208932468511478
xumakikofakumixefotisikunumovudafasofikimozenudafosidaka,749508057657951412178315361964670398839871
dazedokutituzufakebutifokekusobuzutemanesadafadatetitamo,103886097260879003150138325027254855900902
xukemizukozefaxetudizukedimotevubesitekitavukakevutisibe,376136321524704717800574424940622855799327
dozexedivenudifabuvedavebukeketozukumasimakuvetuketomafaxe,42948292938975784099596927092482269526555367
mimasatukidisodifikekutovumazefikefonemofimotesonusazexuxe,43196343143305047528500657761292227037320224
zedafimasobukudizedozefoketuzekisadotufikudadokisakedofoxe,43000150124549846140482724444846720574088407
kisafimosotuvuvuzuzukodibevutemidazusisamokososikomofavuma,2692423943832809210699522830552769656612527
soxutokonebusidaketesomoxemibesonubudibekunumatifokokanemo,2942202721014541374299446744441542204274678
xusikematetemititafafakuxusinekefoketonebetokudonesomosama,2312137916289687577537008913213461971911327
How can I make it so all strings are of length 31 "symbols" (since symbols are 2 characters in this example, that is a total of 62 characters), like this:
xusikematetemititafafakuxusinekexusikematetemititafafakuxusine
That is: What should the 3 large bigint numbers be above in the algorithm? Also, what should they be so the distribution appears random? I noticed that using large numbers close to the boundary resulted in much better apparently-randomized results, compared to smaller numbers. Also, you can't just prefix the bigint x with 0's, which would result in mamamamamama.... Finally, there can at most be 2 pairs of same letters in a sequence, which I assume you can only really solve by just skipping over the results that don't fit that constraint (unless there is some math magic that can somehow tell if more than two of these 32 "symbols" appear next to each other).
Regarding the last part, these are valid results:
mamavumamavumama...
nanavumamavuvuma...
These are not valid:
mamamavumamavuma...
mavuvuvumamavuma...
Because there are 3 pairs in a row that are the same.
To summarize:
How to make it so all strings are 62 characters in length, without padding with zeroes? That means it must fit within some range of BigInts I'm not too sure about.
So that the distribution appears enormously random (i.e. so we don't get just the tail tip of the sequence changing slowly, but instead the entire number seems to completely change, as the examples show).
So that no more than two pairs are similar in a sequence? This part can just be solved by skipping results we find in the pseudo-randomized sequence, unless there is some magic to accomplish it that I'm not possibly fathoming :) For example, maybe there is some magic to do with multiples of similar 5-bit chunks or something, I don't know. But don't need to get fancy, skipping the results that match a regex is fine too.
Here we use Base 32 (hard-coded, but could be parts.length) for the 2 (maxRepeat) least significant digits and Base 31 (hard-coded, but could be parts.length-1) for the remaining digits. This gives the maximum range of values for the length.
All values from 0n to getMax(), inclusive, can be encoded to 31 (minLength) symbols.
The magic for preventing repeats longer than maxRepeat is to check the ith digit against the i - maxRepeat digit, making an adjustment to the ith digit if >=. While this produces valid encodings (ones that follow the rules), not all arbitrary symbol sequences are valid, even if they follow the rules. For example, the sequence mimami would never be generated and wouldn't be decode-able.
const split = new RegExp(`.{2}`, 'g');
const parts = 'mimamonenudidadobebutitetatotukikekakokusisasozezufifafovevuxexu'.match(split);
const partsMap = Object.fromEntries(parts.map((v,i) => ([v,BigInt(i)])));
const encode = (value, maxRepeat = 2, minLength = 31) => {
value = BigInt(value);
const digits = [];
// convert the value to digits
// the first least significant `maxRepeat` digits use base 32, the rest use base 31
while(value > 0) {
const radix = digits.length < maxRepeat ? 32n : 31n;
digits.push(value % radix);
value /= radix;
}
// add 0 padding
while(digits.length < minLength) {
digits.push(0n);
}
// adjust digits to prevent sequences longer than `maxRepeat`
const symbols = []
digits.forEach((v,i) => {
symbols.push((i < maxRepeat || v < symbols[i-maxRepeat]) ? v : v+1n);
});
// map to symbols and return string
const str = symbols.map(v => parts[v]).join('');
return str;
};
const decode = (str, maxRepeat = 2) => {
// split string into array of symbols
const symbols = str.match(split);
// convert symbols to digits
const digits = symbols.map(v => partsMap[v]).map((v,i,a) => {
if(i < maxRepeat || v < a[i-maxRepeat]) return v;
return v-1n;
});
// compute the threshold where we transition from base 31 to base 32
const threshold = digits.length - maxRepeat;
// convert digits to BigInt
const results = digits.reverse().reduce(
(s,v,i) => (s * (i >= threshold ? 32n : 31n) + v)
, 0n);
return results;
};
// compute the maximum value that can be encoded using `minLength` number of symbols
const getMax = (maxRepeat = 2, minLength = 31) => 32n ** BigInt(maxRepeat) * 31n ** BigInt(minLength - maxRepeat) - 1n;
// Consoles will print BigInt but Stackoverflow's interpreter
// doesn't understand them yet so we use `.toString()`.
console.log('limit:', getMax().toString());
console.log(encode(getMax()));
const n1 = 6038940986212279582529645303138677298679151n;
console.log(encode(n1)); // 'kitefitifomazekosaxubezutatudofotudimidanemadanumasisivebumimi'
const n2 = 0n;
console.log(encode(n2)); // 'mimimamamimimamamimimamamimimamamimimamamimimamamimimamamimima'
const s1 = 'kitefitifomazekosaxubezutatudofotudimidanemadanumasisivebumimi';
console.log(decode(s1).toString()); // 6038940986212279582529645303138677298679151
const s2 = 'mimimamamimimamamimimamamimimamamimimamamimimamamimimamamimima';
console.log(decode(s2).toString()); // 0
console.log(decode(encode(0n)) == 0n);
console.log(decode(encode(6038940986212279582529645303138677298679151n)) == 6038940986212279582529645303138677298679151n);
.as-console-wrapper { max-height: 100% !important; top: 0; }

javascript external called function does not return value [duplicate]

Im solving a codewars problem and im pretty sure i've got it working:
function digital_root(n) {
// ...
n = n.toString();
if (n.length === 1) {
return parseInt(n);
} else {
let count = 0;
for (let i = 0; i < n.length; i++) {
//console.log(parseInt(n[i]))
count += parseInt(n[i]);
}
//console.log(count);
digital_root(count);
}
}
console.log(digital_root(942));
Essentially it's supposed to find a "digital root":
A digital root is the recursive sum of all the digits in a number.
Given n, take the sum of the digits of n. If that value has two
digits, continue reducing in this way until a single-digit number is
produced. This is only applicable to the natural numbers.
So im actually getting the correct answer at the end but for whatever reason on the if statement (which im watching the debugger run and it does enter that statement it will say the return value is the correct value.
But then it jumps out of the if statement and tries to return from the main digital_root function?
Why is this? shouldn't it break out of this when it hits the if statement? Im confused why it attempt to jump out of the if statement and then try to return nothing from digital_root so the return value ends up being undefined?
You're not returning anything inside else. It should be:
return digital_root(count);
^^^^^^^
Why?
digital_root is supposed to return something. If we call it with a one digit number, then the if section is executed, and since we return from that if, everything works fine. But if we provide a number composed of more than one digit then the else section get executed. Now, in the else section we calculate the digital_root of the count but we don't use that value (the value that should be returned). The line above could be split into two lines of code that makes it easy to understand:
var result = digital_root(count); // get the digital root of count (may or may not call digital_root while calculating it, it's not owr concern)
return result; // return the result of that so it can be used from the caller of digital_root
Code review
My remarks is code comments below
// javascript generally uses camelCase for function names
// so this should be digitalRoot, not digital_root
function digital_root(n) {
// variable reassignment is generally frowned upon
// it's somewhat silly to convert a number to a string if you're just going to parse it again
n = n.toString();
if (n.length === 1) {
// you should always specify a radix when using parseInt
return parseInt(n);
} else {
let count = 0;
for (let i = 0; i < n.length; i++) {
//console.log(parseInt(n[i]))
count += parseInt(n[i]);
}
// why are you looping above but then using recursion here?
// missing return keyword below
digital_root(count);
}
}
console.log(digital_root(942));
Simple recursive solution
With some of those things in mind, let's simplify our approach to digitalRoot...
const digitalRoot = n =>
n < 10 ? n : digitalRoot(n % 10 + digitalRoot((n - n % 10) / 10))
console.log(digitalRoot(123)) // => 6
console.log(digitalRoot(1234)) // 10 => 1
console.log(digitalRoot(12345)) // 15 => 6
console.log(digitalRoot(123456)) // 21 => 3
console.log(digitalRoot(99999999999)) // 99 => 18 => 9
Using reduce
A digital root is the recursive sum of all the digits in a number. Given n, take the sum of the digits of n. If that value has two digits, continue reducing in this way until a single-digit number is produced. This is only applicable to the natural numbers.
If you are meant to use an actual reducing function, I'll show you how to do that here. First, we'll make a toDigits function which takes an integer, and returns an Array of its digits. Then, we'll implement digitalRoot by reducing those those digits using an add reducer initialized with the empty sum, 0
// toDigits :: Int -> [Int]
const toDigits = n =>
n === 0 ? [] : [...toDigits((n - n % 10) / 10), n % 10]
// add :: (Number, Number) -> Number
const add = (x,y) => x + y
// digitalRoot :: Int -> Int
const digitalRoot = n =>
n < 10 ? n : digitalRoot(toDigits(n).reduce(add, 0))
console.log(digitalRoot(123)) // => 6
console.log(digitalRoot(1234)) // 10 => 1
console.log(digitalRoot(12345)) // 15 => 6
console.log(digitalRoot(123456)) // 21 => 3
console.log(digitalRoot(99999999999)) // 99 => 18 => 9
its a recursive function the code should be somewhat like this
function digital_root(n) {
// ...
n=n.toString();
if(n.length === 1){
return parseInt(n);
}
else
{
let count = 0;
for(let i = 0; i<n.length;i++)
{
//console.log(parseInt(n[i]))
count+=parseInt(n[i]);
}
//console.log(count);
return digital_root(count);
}
}
you should return the same function instead of just calling it to get the correct call stack

Why is my function sometimes squaring twice?

Writing a function to take a number, square each number and return them as a concatenated integer, ie. 3214 => 94116. For some reason, my code appears to occasionally square 2's and 3's twice making a 2 turn into 16 and 3 into 81. I can't figure it out. I'm not a super experienced debugger yet so any help would be appreciated.
function squareDigits(num){
let digits = (""+num).split("");
let intDigits = [];
for (x of digits) {
intDigits.push(parseInt(x));
}
for (x of intDigits) {
intDigits.splice(intDigits.indexOf(x), 1, x * x);
}
return parseInt(intDigits.join(""));
}
console.log(squareDigits(24));
Leaving aside the fact that you can do this more elegantly with something like map() the issue in your code is that it uses indexOf() while changing the values on each iteration. Since indexOf() returns the index of the first occurrence it is going to find digits that you have already replaced.
This is your original code with a few logs so you can understand what I mean:
function squareDigits(num){
let digits = (""+num).split("");
let intDigits = [];
for (x of digits) {
intDigits.push(parseInt(x));
}
for (x of intDigits) {
console.log('intDigits: ' + intDigits);
console.log(` index of ${x} = ${intDigits.indexOf(x)}`);
intDigits.splice(intDigits.indexOf(x), 1, x * x);
}
return parseInt(intDigits.join(""));
}
console.log('RESULT: ' + squareDigits(24));
Notice how in the second pass the index of 4 is 0 (the first position in the array) because you have replaced the original 2 by it's squared value 4.
A simple way to fix this is to not rely on indexOf() and iterate over the array the good old way, like this:
function squareDigits(num){
let digits = (""+num).split("");
let intDigits = [];
for (x of digits) {
intDigits.push(parseInt(x));
}
for (let i = 0; i < intDigits.length; i++) {
const x = intDigits[i];
console.log('intDigits: ' + intDigits);
console.log(` index of ${x} = ${i}`);
intDigits.splice(i, 1, x * x);
}
return parseInt(intDigits.join(""));
}
console.log('RESULT: ' + squareDigits(24));
A simplistic (and bug free) version of your function could be this:
const squareDigits = num => [...num.toString()].map(x => x ** 2).join('');
console.log(squareDigits(24));
Other variant:
const squareDigits = num => num.toString().replaceAll(/\d/g, x => x ** 2);
console.log(squareDigits(24));
Instead of looping twice use array methods .map() , .reduce() etc it will make your code effective .. wrote a simple function
See =>
function squareDigits(num){
let digits = String(num).split("");
digits = digits.reduce((final , digit)=> final += String( parseInt(digit) **2 ), "");
return digits
}
console.log(squareDigits(312));
As #Sebastian mentioned, intDigits.indexOf(x) will find the
first index. So after replacing the first one, there's a change you'll find the number you've just replaced.
We can simplify the function to :
function squareDigits(num){
return num.toString().split('').map(n => n ** 2).join('');
}
Where :
We convert the number to a string using toString()
We split the string into loose numbers using split('')
map() over each number
Return the square by using the Exponentiation (**) operator
join() the numbers to get the result
Example snippet:
function squareDigits(num){
return num.toString().split('').map(n => n ** 2).join('');
}
console.log(squareDigits(3214)); // 94116

Multiplying digits within a number - excluding zeros

I have function taken from this example here that works well, except does not address any zeros that may be in the number, so everything is equaling zero when executing the function.
Multiplying individual digits in a number with each other in JavaScript
function digitsMultip(data) {
let arr = [];
for (let i of data) {
if (data[i] === 0) {
arr.push(data[i]);
}
}
return [...data.toString()].reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));
I added to it a for-loop that accounts for the zero and remove it, but im doing something wrong here.
Uncaught TypeError: data is not iterable
DESIRED OUTPUT
3025 => 3 * 2 * 5 = 30
This iterates over the characters in your number. If the character is not "0" then it is added to the array. This array is then reduced by multiplying the values and then returned.
function digitsMultip(data) {
const arr = [];
for(let number of String(data)) {
if (number !== "0")
arr.push(number);
}
return arr.reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));
You are getting that error because you are trying to iterate over a number.
Passing in a string or converting the number to string before iterating it would make it work.
Instead of looping it that way, a better and readable way would be to use the filter method to filter out the chars before multiplying:
function digitsMultip(data) {
return [...data.toString()].filter(n => n > '0').reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));
Turn the input into a string, then split, filter the zeros and reduce multiplying
const input = 1203
const removeZeros = number =>{
const arr = number.toString().split('').filter(i => i !== '0')
return arr.reduce((a,c) => parseInt(a) * parseInt(c))
}
console.log(removeZeros(input))
One line version
const removeZeros = n => [...n.toString()].filter(c => c !== '0').map(x => parseInt(x)).reduce((a,c) => a*c)

Javascript recursive function not returning value?

Im solving a codewars problem and im pretty sure i've got it working:
function digital_root(n) {
// ...
n = n.toString();
if (n.length === 1) {
return parseInt(n);
} else {
let count = 0;
for (let i = 0; i < n.length; i++) {
//console.log(parseInt(n[i]))
count += parseInt(n[i]);
}
//console.log(count);
digital_root(count);
}
}
console.log(digital_root(942));
Essentially it's supposed to find a "digital root":
A digital root is the recursive sum of all the digits in a number.
Given n, take the sum of the digits of n. If that value has two
digits, continue reducing in this way until a single-digit number is
produced. This is only applicable to the natural numbers.
So im actually getting the correct answer at the end but for whatever reason on the if statement (which im watching the debugger run and it does enter that statement it will say the return value is the correct value.
But then it jumps out of the if statement and tries to return from the main digital_root function?
Why is this? shouldn't it break out of this when it hits the if statement? Im confused why it attempt to jump out of the if statement and then try to return nothing from digital_root so the return value ends up being undefined?
You're not returning anything inside else. It should be:
return digital_root(count);
^^^^^^^
Why?
digital_root is supposed to return something. If we call it with a one digit number, then the if section is executed, and since we return from that if, everything works fine. But if we provide a number composed of more than one digit then the else section get executed. Now, in the else section we calculate the digital_root of the count but we don't use that value (the value that should be returned). The line above could be split into two lines of code that makes it easy to understand:
var result = digital_root(count); // get the digital root of count (may or may not call digital_root while calculating it, it's not owr concern)
return result; // return the result of that so it can be used from the caller of digital_root
Code review
My remarks is code comments below
// javascript generally uses camelCase for function names
// so this should be digitalRoot, not digital_root
function digital_root(n) {
// variable reassignment is generally frowned upon
// it's somewhat silly to convert a number to a string if you're just going to parse it again
n = n.toString();
if (n.length === 1) {
// you should always specify a radix when using parseInt
return parseInt(n);
} else {
let count = 0;
for (let i = 0; i < n.length; i++) {
//console.log(parseInt(n[i]))
count += parseInt(n[i]);
}
// why are you looping above but then using recursion here?
// missing return keyword below
digital_root(count);
}
}
console.log(digital_root(942));
Simple recursive solution
With some of those things in mind, let's simplify our approach to digitalRoot...
const digitalRoot = n =>
n < 10 ? n : digitalRoot(n % 10 + digitalRoot((n - n % 10) / 10))
console.log(digitalRoot(123)) // => 6
console.log(digitalRoot(1234)) // 10 => 1
console.log(digitalRoot(12345)) // 15 => 6
console.log(digitalRoot(123456)) // 21 => 3
console.log(digitalRoot(99999999999)) // 99 => 18 => 9
Using reduce
A digital root is the recursive sum of all the digits in a number. Given n, take the sum of the digits of n. If that value has two digits, continue reducing in this way until a single-digit number is produced. This is only applicable to the natural numbers.
If you are meant to use an actual reducing function, I'll show you how to do that here. First, we'll make a toDigits function which takes an integer, and returns an Array of its digits. Then, we'll implement digitalRoot by reducing those those digits using an add reducer initialized with the empty sum, 0
// toDigits :: Int -> [Int]
const toDigits = n =>
n === 0 ? [] : [...toDigits((n - n % 10) / 10), n % 10]
// add :: (Number, Number) -> Number
const add = (x,y) => x + y
// digitalRoot :: Int -> Int
const digitalRoot = n =>
n < 10 ? n : digitalRoot(toDigits(n).reduce(add, 0))
console.log(digitalRoot(123)) // => 6
console.log(digitalRoot(1234)) // 10 => 1
console.log(digitalRoot(12345)) // 15 => 6
console.log(digitalRoot(123456)) // 21 => 3
console.log(digitalRoot(99999999999)) // 99 => 18 => 9
its a recursive function the code should be somewhat like this
function digital_root(n) {
// ...
n=n.toString();
if(n.length === 1){
return parseInt(n);
}
else
{
let count = 0;
for(let i = 0; i<n.length;i++)
{
//console.log(parseInt(n[i]))
count+=parseInt(n[i]);
}
//console.log(count);
return digital_root(count);
}
}
you should return the same function instead of just calling it to get the correct call stack

Categories

Resources