type conversion not working javascript - javascript

I created a rather large function that takes in an argument, and based on the number's size, properly formats it. It works as expected for any values with the typeof number, however there are a few instances where I need to convert a string to a numeric value. I am trying to do that by using parseInt if its type is not number. When I console.log after the first if-statement, it says its typeof is now number. However when any string is passed through, say, "10000", it just shows up as 10000, and not the expected output of 10,000 with the proper formatting. Below is my code...are there any glaring ways that I might be going about it wrong?
function formatNumber(number) {
if (typeof number !== 'number') {
number = parseInt(number);
return number;
}
let decimals = 2;
const isNegative = number < 0;
const rounded = (number >= 1e+6) ? Math.round(number) : number;
const isInteger = () => parseInt(number, 10) === parseFloat(number);
const abs = Math.abs(rounded);
if (abs < 1e+6) {
decimals = isInteger(abs) ? 0 : decimals;
}
const formatter = val => {
const string = Math.abs(val).toString();
let formatted = '';
for (let i = string.length - 1, d = 1; i >= 0; i--, d++) {
formatted = string[i] + formatted;
if (i > 0 && d % 3 === 0) {
formatted = `,${formatted}`;
}
}
return formatted;
};
const formatLargeNumbers = (value, decimalPlaces) => {
let adjustedValue;
if (value >= 1e+12) {
adjustedValue = parseFloat((value / 1e+12).toFixed(decimals));
return `<span title=${formatter(value)}>${adjustedValue}T</span>`;
}
if (value >= 1e+9) {
adjustedValue = parseFloat((value / 1e+9).toFixed(decimals));
return `<span title=${formatter(value)}>${adjustedValue}B</span>`;
}
if (value >= 1e+6) {
adjustedValue = parseFloat((value / 1e+6).toFixed(decimals));
return `<span title=${formatter(value)}>${adjustedValue}M</span>`;
}
if (value >= 1e+3 && value < 1e+6) {
return value.toLocaleString('en-EN', {
minimumFractionDigits: decimalPlaces,
maximumFractionDigits: decimalPlaces,
});
}
return value.toFixed(decimals);
};
if (isNegative) {
let negativeNumber = Math.abs(rounded);
if (negativeNumber >= 1e+3) {
negativeNumber = formatLargeNumbers(negativeNumber);
}
return `<span class="negative-value">(${negativeNumber})</span>`;
}
return formatLargeNumbers(rounded, decimals);
}

Related

generate random numbers in specific range and using specific numbers?

How to generate random numbers in specific range and using specific numbers?
Example
given numbers [7,8];
given range [100-900];
output must be one of them 777, 787, 788, 878, 877, 888 etc...
Help me
const randomGenerateNumber = (maxRange:number, minRange:number, numbers:number[]) => {
//...what should i do in there??? Help me? Any Idea?
}
I think you don't want random numbers. It seems that you want a set of numbers based on some rules. Random means something else.
If I understand well your question you want to generate all possible numbers containing only a set of digits from a range of numbers. Is this an accurate description?
If so, this is similar with what you want: Generate random numbers only with specific digits
Edit:
You are right, so you want only one number.
In javascript you could do something like this:
I edited the algorithm to take into account min and max in probably the most lazy way. I didn't take into account cases where numbers can't be generated, it will return undefined.
There are so many ways to do this. Your algorithm can work too and maybe more efficient but it seems to have an issue with 0, it will generate numbers with 0 even if it's not in the digits array.
function randomGenerateNumber(minRange, maxRange, digits){
noTries = 0;
while(noTries++ < 100000)
{
var num = 0;
//get a random number from your range
len = Math.floor(Math.random() * (maxRange - minRange) + minRange);
//get the lenght of that random number
len = len.toString().length;
//generate a number with that length using only your set of digits
while(len--)
{
num = num * 10 + digits[Math.floor(Math.random() * digits.length)];
}
if(num >= minRange && num<= maxRange)
{
return num;
break;
}
}
}
//your testing cases
console.log(randomGenerateNumber(100,900,[7,8]))
console.log(randomGenerateNumber(299,300,[1,2,3,4,5,6,7,8,9]));
i did it. Is there any improvement. Little bit messy.
const getRandomNumber = (min: number, max: number, numbers: number[]): number => {
if (numbers.length === 9) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
let result = '';
//split maxDigits 100 => [1, 0, 0]
const maxDigits = max
.toString()
.split('')
.map(i => parseInt(i, 10));
//split minDigits 100 => [1, 0, 0]
const minDigits = min
.toString()
.split('')
.map(i => parseInt(i, 10));
//length of random number [minDigit, maxDigit] inclusive
const randomDigit = Math.floor(Math.random() * (maxDigits.length - minDigits.length + 1) + minDigits.length);
let alreadyHigh = false;
let alreadyLow = false;
let equal = true;
//4 conditions
//1. minDigits.length === maxDigits.length
//2. randomDigit === minDigits.length
//3. randomDigit === maxDigits.length
//4. randomDigit > minDigits.length && randomDigit < maxDigits.length
for (let i = 0; i < randomDigit; i++) {
const numbersToUse = i === 0 ? numbers : [...numbers, 0];
let availableNumbers = [];
if (minDigits.length === maxDigits.length) {
if (equal) {
for (let k = 0; k < numbersToUse.length; k++) {
if (minDigits[i] > maxDigits[i]) {
if (numbersToUse[k] >= 0 && numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
} else if (numbersToUse[k] >= minDigits[i] && numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
} else {
availableNumbers.push(maxDigits[i]);
}
}
} else {
if (!alreadyHigh) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] >= minDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
}
} else if (randomDigit === minDigits.length) {
if (!alreadyHigh) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] >= minDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
} else if (randomDigit === maxDigits.length) {
if (!alreadyLow) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
} else {
availableNumbers = numbersToUse;
}
availableNumbers = [...new Set(availableNumbers)];
const randomIndex = Math.floor(Math.random() * availableNumbers.length);
result += `${availableNumbers[randomIndex]}`;
alreadyHigh = !alreadyHigh ? availableNumbers[randomIndex] > minDigits[i] : true;
alreadyLow = !alreadyLow ? availableNumbers[randomIndex] < maxDigits[i] : true;
equal = equal ? availableNumbers[randomIndex] === maxDigits[i] : false;
}
return parseInt(result, 10);
};

Adding Strings With Float Numbers Javascript

I'm trying to solve a question to be able to add strings that include floating point numbers. For example "110.75" + "9" = "119.75".
I have the code below that I have been wrestling with for about an hour now and could appreciate if anybody could point me in the right direction as to where I might be wrong. I am only returning an empty string "" for every test case I write for myself.
var addStrings = function(num1, num2) {
const zero = 0;
let s1 = num1.split(".");
let s2 = num2.split(".");
result = "";
let sd1 = s1.length > 1 ? s1[1] : zero;
let sd2 = s2.length > 1 ? s2[1] : zero;
while(sd1.length !== sd2.length) {
if(sd1.length < sd2.length) {
sd1 += zero
} else {
sd2 += zero;
}
}
let carry = addStringHelper(sd1, sd2, result, 0);
result.concat(".");
addStringHelper(s1[0], s2[0], result, carry);
return result.split("").reverse().join("");
};
function addStringHelper(str1, str2, result, carry) {
let i = str1.length - 1;
let j = str2.length - 1;
while(i >= 0 || j >= 0) {
let sum = carry
if(j >= 0) {
sum += str1.charAt(j--) - '0';
}
if(i >= 0 ) {
sum += str2.charAt(i--) - '0';
}
carry = sum / 10;
result.concat(sum % 10);
}
return carry
}
Convert the strings into Number, add them and then convert them back to String.
const addStrings = (num1, num2) => String(Number(num1) + Number(num2))
console.log(addStrings("110.67", "9"))
Also, try to handle floating point rounding in some way. You can try using toFixed (this will fix the result to two decimal places).
const addStrings = (num1, num2) => String((Number(num1) + Number(num2)).toFixed(2))
console.log(addStrings("0.2", "0.1"))

Get binary representation of integer

I just had an interview question, where I need to get the binary representation of an integer, this is something I should know how to do.. for example, 5 is represented in binary as 101, and the steps look something like:
// 5 % 2 = 1
// 5 / 2 = 2
// result = 1;
// 2 % 2 = 0
// 2 / 2 = 1
// result = 10
// 1 % 2 = 1
// 1 / 2 = 0
// result = 101
the stopping condition is when ~~(1/2) === 0
so I have this:
const getBinary = (v) => {
let remainder, binary = 1;
while (true) {
remainder = v % 2;
v = ~~(v / 2);
if (v === 0) {
return binary;
}
if (remainder === 0) {
binary = binary * 10 + 1;
}
else {
binary = binary * 10;
}
}
};
console.log(getBinary(5));
so that works, but the binary variable is initialized to 1. Is there a way to improve this so it works with negative numbers, or if 0 is passed as the argument to the function?
var integer = 52;
console.log(integer.toString(2));
Simple function native to javascript, no lengthy code required.
If you want to write it from scratch you can use something like this:
function toBinary(n) {
n = Number(n);
if (n == 0) return '0';
var r = '';
while (n != 0) {
r = ((n&1)?'1':'0') + r;
n = n >>> 1;
}
return r;
}
console.log(toBinary(5));
console.log(toBinary(10));
console.log(toBinary(-5));
console.log(toBinary(0));
So here is one way. It has an inner function that handles the basics and an outer one that extends to your special cases. I preferred to do string representations.
const getBinary = v => {
if (v === 0) return '';
let remainder = v % 2;
let quotient = (v - remainder) / 2;
if (remainder === 0) {
return getBinary(quotient) + '0';
}
else {
return getBinary(quotient) + '1';
}
}
const betterGetBinary = v => {
if (v === 0) return '0';
if (v < 0) return '-' + getBinary(-v);
return getBinary(v);
}
console.log(betterGetBinary(-10));
A quick and dirty solution, although it 'might' have two flaws:
- Math.floor()
- no bitwise operator
let getBinary = number => {
let done = false;
let resultInverted = [];
let acc = number;
while (!done) {
let reminder = acc % 2;
if (acc === 1) {
done = true;
}
acc = Math.floor(acc / 2);
resultInverted.push(reminder);
}
return Number(resultInverted.reverse().join(''));
};
console.log(typeof getBinary(2));
console.log(getBinary(5));
console.log(getBinary(127));

Subset sum with number reuse allowed

I have a list of positive integers e.g. 15, 29, 110, and a target e.g. 44. I'm trying to find all possible combinations which sum to the target but importantly, the numbers in the set can be used multiple times e.g.
Target = 44
Result = 1x15, 1x29
Target = 307
Result = 2x110, 3x29
I found a dynamic programming solution which works when the combination is no more than one of each number. So Target 44 works but not my 307 example (returns Not Found).
How can the multiples or number reuse be done?
function subset(people, min, max)
{
var subsets = [];
subsets[0] = '';
for (var person in people)
{
for (var s = min-1; s >= 0; --s)
{
if (s in subsets)
{
var sum = s + people[person];
if (!(sum in subsets))
{
subsets[sum] = subsets[s] + ' ' + person;
if (sum >= min && sum <= max)
{
return subsets[sum];
}
}
}
}
}
return 'Not found';
}
var p = {
optionA:15,
optionB:29,
optionC:110
};
var qty = 307;
console.log(subset(p, qty, qty));
Try this recursive solution:
function subset(people, min, max) {
const pairs = Object.entries(people),
results = [],
getSum = multiplications => multiplications.reduce((sum, multiplicator, position) =>
sum + pairs[position][1] * multiplicator, 0),
formatResult = result => result.map(multiplications =>
multiplications.reduce((res, multiplicator, position) =>
(multiplicator > 0 ? res.push(`${multiplicator}x${pairs[position][1]}`) :
res, res), []));
function findSums(multiplications, position) {
let s;
while((s = getSum(multiplications)) <= max) {
if (s >= min) {
results.push([...multiplications]);
}
if (position < pairs.length - 1) {
const m = [...multiplications],
nextPosition = position + 1;
m[nextPosition]++;
findSums(m, nextPosition);
}
multiplications[position]++;
}
}
findSums(pairs.map(_ => 0), 0);
return results.length > 0 ? formatResult(results) : "Not found";
}
var p = {
optionA:15,
optionB:29,
optionC:110
};
var qty = 307;
console.log(subset(p, qty, qty));
Change the second loop in such way:
for (var s = 0; s <= wantedSum - people[person] ; s++)
Using this approach you fill all entries of subsets[] array\list where index is multiple of people[person] (instead of single entry). For example, with value 3 you fill 3,6,9,12... entries.

How can I round to an arbitrary number of significant digits with JavaScript?

I tried below sample code
function sigFigs(n, sig) {
if ( n === 0 )
return 0
var mult = Math.pow(10,
sig - Math.floor(Math.log(n < 0 ? -n: n) / Math.LN10) - 1);
return Math.round(n * mult) / mult;
}
But this function is not working for inputs like
sigFigs(24730790,3) returns 24699999.999999996
and sigFigs(4.7152e-26,3) returns: 4.7200000000000004e-26
If anybody has working example please share.
Thanks.
You can try javascript inbuilt method-
Number( my_number.toPrecision(3) )
For Your case try
Number( 24730790.0.toPrecision(5) )
For your refrence and working example you can see link
First of all thanks to everybody, it would be a hard task without these snippets shared.
My value added, is the following snippet (see below for complete implementation)
parseFloat(number.toPrecision(precision))
Please note that if number is, for instance, 10000 and precision is 2, then number.toPrecision(precision) will be '1.0e+4' but parseFloat understands exponential notation.
It is also worth to say that, believe it or not, the algorithm using Math.pow and logarithms posted above, when run on test case formatNumber(5, 123456789) was giving a success on Mac (node v12) but rising and error on Windows (node v10). It was weird so we arrived at the solution above.
At the end I found this as the definitive implementation, taking advantage of all feedbacks provided in this post. Assuming we have a formatNumber.js file with the following content
/**
* Format number to significant digits.
*
* #param {Number} precision
* #param {Number} number
*
* #return {String} formattedValue
*/
export default function formatNumber (precision, number) {
if (typeof number === 'undefined' || number === null) return ''
if (number === 0) return '0'
const roundedValue = round(precision, number)
const floorValue = Math.floor(roundedValue)
const isInteger = Math.abs(floorValue - roundedValue) < Number.EPSILON
const numberOfFloorDigits = String(floorValue).length
const numberOfDigits = String(roundedValue).length
if (numberOfFloorDigits > precision) {
return String(floorValue)
} else {
const padding = isInteger ? precision - numberOfFloorDigits : precision - numberOfDigits + 1
if (padding > 0) {
if (isInteger) {
return `${String(floorValue)}.${'0'.repeat(padding)}`
} else {
return `${String(roundedValue)}${'0'.repeat(padding)}`
}
} else {
return String(roundedValue)
}
}
}
function round (precision, number) {
return parseFloat(number.toPrecision(precision))
}
If you use tape for tests, here there are some basic tests
import test from 'tape'
import formatNumber from '..path/to/formatNumber.js'
test('formatNumber', (t) => {
t.equal(formatNumber(4, undefined), '', 'undefined number returns an empty string')
t.equal(formatNumber(4, null), '', 'null number return an empty string')
t.equal(formatNumber(4, 0), '0')
t.equal(formatNumber(4, 1.23456789), '1.235')
t.equal(formatNumber(4, 1.23), '1.230')
t.equal(formatNumber(4, 123456789), '123500000')
t.equal(formatNumber(4, 1234567.890123), '1235000')
t.equal(formatNumber(4, 123.4567890123), '123.5')
t.equal(formatNumber(4, 12), '12.00')
t.equal(formatNumber(4, 1.2), '1.200')
t.equal(formatNumber(4, 1.234567890123), '1.235')
t.equal(formatNumber(4, 0.001234567890), '0.001235')
t.equal(formatNumber(5, 123456789), '123460000')
t.end()
})
How about automatic type casting, which takes care of exponential notation?
f = (x, n) => +x.toPrecision(n)
Testing:
> f (0.123456789, 6)
0.123457
> f (123456789, 6)
123457000
> f (-123456789, 6)
-123457000
> f (-0.123456789, 6)
-0.123457
> f (-0.123456789, 2)
-0.12
> f (123456789, 2)
120000000
And it returns a number and not a string.
Unfortunately the inbuilt method will give you silly results when the number is > 10, like exponent notation etc.
I made a function, which should solve the issue (maybe not the most elegant way of writing it but here it goes):
function(value, precision) {
if (value < 10) {
value = parseFloat(value).toPrecision(precision)
} else {
value = parseInt(value)
let significantValue = value
for (let i = value.toString().length; i > precision; i--) {
significantValue = Math.round(significantValue / 10)
}
for (let i = 0; significantValue.toString().length < value.toString().length; i++ ) {
significantValue = significantValue * 10
}
value = significantValue
}
return value
}
If you prefer having exponent notation for the higher numbers, feel free to use toPrecision() method.
if you want to specify significant figures left of the decimal place and replace extraneous placeholders with T B M K respectively
// example to 3 sigDigs (significant digits)
//54321 = 54.3M
//12300000 = 12.3M
const moneyFormat = (num, sigDigs) => {
var s = num.toString();
let nn = "";
for (let i = 0; i <= s.length; i++) {
if (s[i] !== undefined) {
if (i < sigDigs) nn += s[i];
else nn += "0";
}
}
nn = nn
.toString()
.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")
.replace(",000,000,000", "B")
.replace(",000,000", "M")
.replace(",000", "k");
if (
nn[nn.length - 4] === "," &&
nn[nn.length - 2] === "0" &&
nn[nn.length - 1] === "0"
) {
let numLetter = "K";
if (parseInt(num) > 999999999999) numLetter = "T";
else if (parseInt(num) > 999999999) numLetter = "B";
else if (parseInt(num) > 999999) numLetter = "M";
console.log("numLetter: " + numLetter);
nn = nn.toString();
let nn2 = ""; // new number 2
for (let i = 0; i < nn.length - 4; i++) {
nn2 += nn[i];
}
nn2 += "." + nn[nn.length - 3] + numLetter;
nn = nn2;
}
return nn;
};

Categories

Resources