how to format string(numbers) printing in javascript - javascript

For example. I want to print numbers from 1 to 20
but I want print 1 as 01 , 2 as 02 and so on ..

formatNumber = function( num )
{
if ( num < 10 )
{
return "0" + num;
}
else
{
return "" + num;
}
}

Here's a generic 'zeroPad' function for you:
function zeroPad(nr,base){
base = base || 10;
var len = (String(base).length - String(nr).length)+1;
return len > 0 ? new Array(len).join('0')+nr : nr;
}
//usage
zeroPad(5); //=> "05"
zeroPad(50,1000); //=> "0050"
zeroPad(50); //=> "50"
or as Number Extension:
Number.prototype.zeroPad = Number.prototype.zeroPad ||
function(base){
base = base || 10;
var len = (String(base).length - String(this).length)+1;
return len > 0 ? new Array(len).join('0')+this : this;
};
//usage
(5).zeroPad(); //=> "05"
(50).zeroPad(1000); //=> "0050"
(50).zeroPad(); //=> "50"

Let's abuse the ternary operator:
for(var n = 1; n <= 20; n++) {
console.log((n < 10 ? '0' : '') + n)
}

Here is shorter version:
leadingZero = function(num){
return (num < 10) ? "0"+num : num;
}

Use String.prototype.padStart:
`${num}`.padStart(2, '0');
From MDN:
The padStart() method pads the current string with another string (repeated, if needed) so that the resulting string reaches the given length. The padding is applied from the start (left) of the current string.
padStart is only defined on strings—not numbers—so you need to cast the number to string (num.toString(); or more idiomatically `${num}`) before you call padStart. The first parameter is the minimum length of the outcome string so if you numbers reach the hundreds do `${num}`.padStart(3, '0').
// Create an array of the numbers 1 through 20.
const arr = Array.from({ length: 20 }, (_, i) => i + 1);
arr.forEach(i => {
// Pad each one digit number with a leading zero.
console.log(`${i}`.padStart(2, '0'));
})

Related

How to count all the palindromes in a string using recursion?

I have a recursive function that checks if a string is a palindrome, but my assignment asks me to count the number of palindromes in a string (for example kayak has 2).
I'm really confused about how I can implement a recursive function that counts the number of palindromes. Here's my current code:
function isPalindrome(string) {
if (string.length <= 1) {
return true;
}
let [ firstLetter ] = string;
let lastLetter = string[string.length - 1];
if (firstLetter === lastLetter) {
let stringWithoutFirstAndLastLetters = string.substring(1, string.length - 1);
return isPalindrome(stringWithoutFirstAndLastLetters);
} else {
return false;
}
}
When the function gets a palindrome it is easy:
Record the input
Try again without the edges
Stop when input is three characters or less
"kayak" -> "aya"
If the input isn't a palindrome try "both ends" recursively e.g. with "kayam" try with both "kaya" and "ayam" and keep going...
We stop the recursion when a string is 3 (or less) characters. A single character is not a palindrome and checking whether a two or three characters string is a palindrome is trivial.
kayam
|
+-------------+
| |
kaya ayam
| |
+-------+ +--------+
| | | |
kay aya aya yam
const reverse =
([...xs]) =>
xs.reverse().join("");
const is_palindrome =
a =>
a.length === 1 ? false
: a.length <= 3 ? a[0] === a[a.length-1]
: a === reverse(a);
const find_palindromes = str => {
const scan =
(x, xs = []) =>
x.length <= 3 ? xs.concat(is_palindrome(x) ? x : [])
: is_palindrome(x) ? xs.concat
( x
, scan(x.slice(1, -1))
)
: xs.concat
( scan(x.slice(0, -1))
, scan(x.slice(1))
);
return [...new Set(scan(str))];
};
console.log(find_palindromes("kayak").join());
console.log(find_palindromes("kayakkayak").join());
console.log(find_palindromes("kayakcanoe").join());
console.log(find_palindromes("kayam").join());
console.log(find_palindromes("appal").join());
console.log(find_palindromes("madamimadam").join());
console.log(find_palindromes("madamimadamkayak").join());
I think the accepted answer does not actually work. It will not count palindromes unless they are centered in the string and will count substrings that are not palindromes if as long as they start and end with the same letter. The answer from CertainPerformance would probably work but I think it would result in checking a lot of strings that don't need to be checked. Here's what I came up with, I think it works for the extra tests I've added.
function countPalindromes(string) {
if (string.length <= 1) {
return 0;
}
count = 0
for ( var i = 0; i < string.length; i++ ) {
count += countPalindromesCenteredAt(string, i)
count += countPalindromesCenteredAfter(string, i)
}
return count
}
function countPalindromesCenteredAt(string, i) {
count = 0
for ( var j = 1; i-j>=0 && i+j < string.length; j++ ) {
if (string.charAt(i-j) === string.charAt(i+j)) {
count += 1
}
else {
return count
}
}
return count
}
function countPalindromesCenteredAfter(string, i) {
count = 0
for ( var j = 1; i-j>=0 && i+j < string.length; j++ ) {
if (string.charAt(i-j+1) === string.charAt(i+j)) {
count += 1
}
else {
return count
}
}
return count
}
console.log(countPalindromes("kayak"));
console.log(countPalindromes("aya"));
console.log(countPalindromes("kayakcanoe"));
console.log(countPalindromes("kcanoek"));
One method would be to first get all substrings, then validate each:
getAllSubstrings('kayak').filter(str => str.length >= 2 && isPalindrome(str))
function getAllSubstrings(str) {
var i, j, result = [];
for (i = 0; i < str.length; i++) {
for (j = i + 1; j < str.length + 1; j++) {
result.push(str.slice(i, j));
}
}
return result;
}
function isPalindrome(string) {
if (string.length <= 1) {
return true;
}
let [ firstLetter ] = string;
let lastLetter = string[string.length - 1];
if (firstLetter === lastLetter) {
let stringWithoutFirstAndLastLetters = string.substring(1, string.length - 1);
return isPalindrome(stringWithoutFirstAndLastLetters);
} else {
return false;
}
}
console.log(
getAllSubstrings('kayak').filter(str => str.length >= 2 && isPalindrome(str))
);
Here's an answer similar to that from CertainPerformance, but using recursion for the helper functions:
const getSubstrings = (str) =>
str .length == 0
? []
: [
... str .split ('') .map ((_, i) => str .slice (0, str .length - i)),
... getSubstrings (str .slice (1))
]
const isPalindrome = (str) =>
str .length < 2
? true
: str [0] === str .slice (-1) [0] && isPalindrome (str .slice (1, -1))
const getPalindromicSubstrings = (str) =>
getSubstrings (str)
.filter (s => s.length > 1)
.filter (isPalindrome)
const countPalindromicSubstrings = (str) =>
getPalindromicSubstrings (str) .length
const countUniquePalindromicSubstrings = (str) =>
new Set(getPalindromicSubstrings (str)) .size
console .log (getPalindromicSubstrings ('madamimadam'))
console .log (countPalindromicSubstrings ('madamimadam'))
console .log (countUniquePalindromicSubstrings ('madamimadam'))
.as-console-wrapper {max-height: 100% !important; top: 0}
getSubstrings does just what you'd expect. getSubstrings('abcd') returns ["abcd", "abc", "ab", "a", "bcd", "bc", "b", "cd", "c", "d"].
isPalindrome says that the empty string and single-character strings are automatically palindromes and that for another string we check that the two end characters match, recurring on the remainder.
getPalindromicSubstrings finds all the substrings that are palindromes, skipping those of length 1.
countPalindromicSubstrings returns a count of those.
countUniquePalindromicSubstrings uses a Set to filter out duplicates and returns that count.
We could also easily write a getUniquePalindromicSubstrings in a similar manner if needed.
getSubstrings is the only function with any complexity. It operates by repeatedly slicing our string from to a value varying from length down to 1, then recurring on the string starting with the second character, stopping when our input is empty.

Recursive function to reverse a number

I tried to use a recursive function to reverse a number it works but for one call only it's because of scoping i guess but i don't know how to fix it
let num;
let reversed='';
let result;
function reverseNum(n){
for(let i =0; i<n; i++){
num = n%10; // get the last digit e.g 352 %10 = 2
reversed+= num
result = parseInt(n / 10); // remove last digit e.g. parseInt(352/10) = 35
reverseNum(result);
if(result ===0){
break;
}
}
return reversed;
}
You need the num, reversed, and result variables to be created anew each time the function is called externally. Here's one simple tweak, by defining the recursive function inside the top reverseNum function:
function reverseNum(n) {
let num;
let reversed = '';
let result;
const recurse = (n) => {
for (let i = 0; i < n; i++) {
num = n % 10; // get the last digit e.g 352 %10 = 2
reversed += num
result = parseInt(n / 10); // remove last digit e.g. parseInt(352/10) = 35
recurse(result);
if (result === 0) {
break;
}
}
return reversed;
};
return recurse(n);
}
console.log(reverseNum(1234));
console.log(reverseNum(1234));
But a more elegant method would be:
function reverseNum(n, str = String(n)) {
const thisDigit = str[str.length - 1];
const recursiveResult = str.length === 1 ? '' : reverseNum(str.slice(0, str.length - 1));
return Number(thisDigit + recursiveResult);
}
console.log(reverseNum(1234));
console.log(reverseNum(1234));
function reverse(number){
let index = 0 ;
let reversed = '';
let max = `${number}`.toString().length-1;
while(index <= max ){
reversed += `${number}`.charAt(max-index)
index ++;
}
return reversed;
}
console.log(reverse(546))
CertainPerformance has explained why your code wasn't working.
Here is another implementation, one I find reasonably simple:
const reverseNum = (n) =>
n < 10
? String(n)
: String (n % 10) + reverseNum (Math .floor (n / 10))
console .log (reverseNum (8675309))
Note that this returns a String rather than a Number. If we wanted to, we could make this a private function and make a public function one which called this and converted the result back into a number. But that would have the weird effect that reversing, say, 1000 would yield 1, since 0001 is simplified to 1. And that would mean that when you reverse again, you don't get anything like your original value. So I choose to keep with a String.
Of course if we're going to do String reversal, perhaps we're better off just using a String reversal function in the first place:
const reverseStr = (s) =>
s.length == 0
? ''
: reverseStr (s .slice (1)) + s [0]
const reverseNum = (n) =>
reverseStr (String(n))
console .log (reverseNum (8675309))
Or if we weren't interested in doing this recursively, we could just write the more common string reversal function:
const reverseStr = (s) =>
s .split ('') .reverse () .join ('')
const reverseNum = (n) =>
reverseStr (String (n))
console .log (reverseNum (8675309))

Convert HEX to Signed INT Javascript [duplicate]

I have a signed value given as a hex number, by example 0xffeb and want convert it into -21 as a "normal" Javascript integer.
I have written some code so far:
function toBinary(a) { //: String
var r = '';
var binCounter = 0;
while (a > 0) {
r = a%2 + r;
a = Math.floor(a/2);
}
return r;
}
function twoscompl(a) { //: int
var l = toBinaryFill(a).length;
var msb = a >>> (l-1);
if (msb == 0) {
return a;
}
a = a-1;
var str = toBinary(a);
var nstr = '';
for (var i = 0; i < str.length; i++) {
nstr += str.charAt(i) == '1' ? '0' : '1';
}
return (-1)*parseInt(nstr);
}
The problem is, that my function returns 1 as MSB for both numbers because only at the MSB of the binary representation "string" is looked. And for this case both numbers are 1:
-21 => 0xffeb => 1111 1111 1110 1011
21 => 0x15 => 1 0101
Have you any idea to implement this more efficient and nicer?
Greetings,
mythbu
Use parseInt() to convert (which just accepts your hex string):
parseInt(a);
Then use a mask to figure out if the MSB is set:
a & 0x8000
If that returns a nonzero value, you know it is negative.
To wrap it all up:
a = "0xffeb";
a = parseInt(a, 16);
if ((a & 0x8000) > 0) {
a = a - 0x10000;
}
Note that this only works for 16-bit integers (short in C). If you have a 32-bit integer, you'll need a different mask and subtraction.
I came up with this
function hexToInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
And usage:
var res = hexToInt("FF"); // -1
res = hexToInt("A"); // same as "0A", 10
res = hexToInt("FFF"); // same as "0FFF", 4095
res = hexToInt("FFFF"); // -1
So basically the hex conversion range depends on hex's length, ant this is what I was looking for. Hope it helps.
Based on #Bart Friederichs I've come with:
function HexToSignedInt(num, numSize) {
var val = {
mask: 0x8 * Math.pow(16, numSize-1), // 0x8000 if numSize = 4
sub: -0x1 * Math.pow(16, numSize) //-0x10000 if numSize = 4
}
if((parseInt(num, 16) & val.mask) > 0) { //negative
return (val.sub + parseInt(num, 16))
}else { //positive
return (parseInt(num,16))
}
}
so now you can specify the exact length (in nibbles).
var numberToConvert = "CB8";
HexToSignedInt(numberToConvert, 3);
//expected output: -840
function hexToSignedInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
function hexToUnsignedInt(hex){
return parseInt(hex,16);
}
the first for signed integer and
the second for unsigned integer
As I had to turn absolute numeric values to int32 values that range from -2^24 to 2^24-1,
I came up with this solution, you just have to change your input into a number through parseInt(hex, 16), in your case, nBytes is 2.
function toSignedInt(value, nBytes) { // 0 <= value < 2^nbytes*4, nBytes >= 1,
var hexMask = '0x80' + '00'.repeat(nBytes - 1);
var intMask = parseInt(hexMask, 16);
if (value >= intMask) {
value = value - intMask * 2;
}
return value;
}
var vals = [ // expected output
'0x00', // 0
'0xFF', // 255
'0xFFFFFF', // 2^24 - 1 = 16777215
'0x7FFFFFFF', // 2^31 -1 = 2147483647
'0x80000000', // -2^31 = -2147483648
'0x80000001', // -2^31 + 1 = -2147483647
'0xFFFFFFFF', // -1
];
for (var hex of vals) {
var num = parseInt(hex, 16);
var result = toSignedInt(num, 4);
console.log(hex, num, result);
}
var sampleInput = '0xffeb';
var sampleResult = toSignedInt(parseInt(sampleInput, 16), 2);
console.log(sampleInput, sampleResult); // "0xffeb", -21
Based on the accepted answer, expand to longer number types:
function parseSignedShort(str) {
const i = parseInt(str, 16);
return i >= 0x8000 ? i - 0x10000 : i;
}
parseSignedShort("0xffeb"); // -21
function parseSignedInt(str) {
const i = parseInt(str, 16);
return i >= 0x80000000 ? i - 0x100000000 : i;
}
parseSignedInt("0xffffffeb"); // -21
// Depends on new JS feature. Only supported after ES2020
function parseSignedLong(str) {
if (!str.toLowerCase().startsWith("0x"))
str = "0x" + str;
const i = BigInt(str);
return Number(i >= 0x8000000000000000n ? i - 0x10000000000000000n : i);
}
parseSignedLong("0xffffffffffffffeb"); // -21

Formatting a number by a decimal

I'm trying to transform an array of numbers such that each number has only one nonzero digit.
so basically
"7970521.5544"
will give me
["7000000", "900000", "70000", "500", "20", "1", ".5", ".05", ".004", ".0004"]
I tried:
var j = "7970521.5544"
var k =j.replace('.','')
var result = k.split('')
for (var i = 0; i < result.length; i++) {
console.log(parseFloat(Math.round(result[i] * 10000) /10).toFixed(10))
}
Any ideas, I'm not sure where to go from here?
Algorithm:
Split the number in two parts using the decimal notation.
Run a for loop to multiply each digit with the corresponding power of 10, like:
value = value * Math.pow(10, index); // for digits before decimal
value = value * Math.pow(10, -1 * index); // for digits after decimal
Then, filter the non-zero elements and concatenate both the arrays. (remember to re-reverse the left-side array)
var n = "7970521.5544"
var arr = n.split('.'); // '7970521' and '5544'
var left = arr[0].split('').reverse(); // '1250797'
var right = arr[1].split(''); // '5544'
for(let i = 0; i < left.length; i++)
left[i] = (+left[i] * Math.pow(10, i) || '').toString();
for(let i = 0; i < right.length; i++)
right[i] = '.' + +right[i] * Math.pow(10, -i);
let res = left.reverse() // reverses the array
.filter(n => !!n)
// ^^^^^^ filters those value which are non zero
.concat(right.filter(n => n !== '.0'));
// ^^^^^^ concatenation
console.log(res);
You can use padStart and padEnd combined with reduce() to build the array. The amount you want to pad will be the index of the decimal minus the index in the loop for items left of the decimal and the opposite on the right.
Using reduce() you can make a new array with the padded strings taking care to avoid the zeroes and the decimal itself.
let s = "7970521.5544"
let arr = s.split('')
let d_index = s.indexOf('.')
if (d_index == -1) d_index = s.length // edge case for nums with no decimal
let nums = arr.reduce((arr, n, i) => {
if (n == 0 || i == d_index) return arr
arr.push((i < d_index)
? n.padEnd(d_index - i, '0')
: '.' + n.padStart(i - d_index, '0'))
return arr
}, [])
console.log(nums)
You could split your string and then utilize Array.prototype.reduce method. Take note of the decimal position and then just pad your value with "0" accordingly. Something like below:
var s = "7970521.5544";
var original = s.split('');
var decimalPosition = original.indexOf('.');
var placeValues = original.reduce((accum, el, idx) => {
var f = el;
if (idx < decimalPosition) {
for (let i = idx; i < (decimalPosition - 1); i++) {
f += "0";
}
accum.push(f);
} else if (idx > decimalPosition) {
let offset = Math.abs(decimalPosition - idx) - 2;
for (let i = 0; i <= offset; i++) {
f = "0" + f;
}
f = "." + f;
accum.push(f);
}
return accum;
}, []);
console.log(placeValues);
Shorter alternative (doesn't work in IE) :
var s = "7970521.5544"
var i = s.split('.')[0].length
var a = [...s].reduce((a, c) => (i && +c && a.push(i > 0 ?
c.padEnd(i, 0) : '.'.padEnd(-i, 0) + c), --i, a), [])
console.log( a )
IE version :
var s = "7970521.5544"
var i = s.split('.')[0].length
var a = [].reduce.call(s, function(a, c) { return (i && +c && a.push(i > 0 ?
c + Array(i).join(0) : '.' + Array(-i).join(0) + c), --i, a); }, [])
console.log( a )
function standardToExpanded(n) {
return String(String(Number(n))
.split(".")
.map(function(n, i) {
// digits, decimals..
var v = n.split("");
// reverse decimals..
v = i ? v.reverse() : v;
v = v
.map(function(x, j) {
// expanded term..
return Number([x, n.slice(j + 1).replace(/\d/g, 0)].join(""));
})
.filter(Boolean); // omit zero terms
// unreverse decimals..
v = i ? v.map(function(x) {
return '.' + String(x).split('').reverse().join('')
}).reverse() : v;
return v;
})).split(',');
}
console.log(standardToExpanded("7970521.5544"));
// -> ["7000000", "900000", "70000", "500", "20", "1", ".5", ".05", ".004", ".0004"]
This looks like something out of my son's old 3rd Grade (core curriculum) Math book!

How to use Javascript math on a version number

I use jQuery to get the browser version like this:
var x = $.browser.version;
I get a string like this: 1.9.1.1
Now, I want to do an evaluation so if x is >= 1.9.1 then do some stuff. Unfortunately, with multiple decimal points, I cannot do a parseFloat() because it converts 1.9.1.1 to simply 1.9, and the if evaluation would match a 1.9.0 version (which I do not want).
Has someone figured out a way to accomplish turning a version number (with multiple decimals) into something that can be used as a number for evaluation (or some other way to accomplish what I am trying to do here)?
Thanks -
You could do something with string.split and then do a digit by digit comparison
// arr[0] = 1
// arr[1] = 9
// arr[2] = 1
// arr[3] = 1
var arr = ($.browser.version).split('.');
The following is taken from this post
This is a function that will parse your version string and give you back a JSON object
function parseVersionString (str) {
if (typeof(str) != 'string') { return false; }
var x = str.split('.');
// parse from string or default to 0 if can't parse
var maj = parseInt(x[0]) || 0;
var min = parseInt(x[1]) || 0;
var bld = parseInt(x[2]) || 0;
var rev = parseInt(x[3]) || 0;
return {
major: maj,
minor: min,
build: bld,
revision: rev
}
}
Then you could use the following syntax
var version = parseVersionString($.browser.version);
// version.major == 1
// version.minor == 9
// version.build == 1
// version.revision == 1
Here's another version of versionCmp():
function versionCmp(v1, v2) {
v1 = String(v1).split('.');
v2 = String(v2).split('.');
var diff = 0;
while((v1.length || v2.length) && !diff)
diff = (+v1.shift() || 0) - (+v2.shift() || 0);
return (diff > 0) - (diff < 0);
}
Another possibility would be to assign a numeric value to each version number:
function valueOfVersion(ver) {
ver = String(ver).split('.');
var value = 0;
for(var i = ver.length; i--;)
value += ver[i] / Math.pow(2, i * 8) || 0;
return value;
}
This only works if each digit is less than 256 (because of the hard-coded divisor) and has a limited precision (ie the version strings can't get arbitrarily long).
You need to treat each portion of the string as a seperate integer, so split and iterate, and cmp:
// perform cmp(a, b)
// -1 = a is smaller
// 0 = equal
// 1 = a is bigger
function versionCmp(a, b) {
a = a.split(".");
b = b.split(".");
for(var i=0; i < a.length; i++) {
av = parseInt(a[i]);
bv = parseInt(b[i]);
if (av < bv) {
return -1;
} else if (av > bv) {
return 1;
}
}
return 0;
}
console.log(versionCmp("1.1.2.3", "1.2.1.0")); // should be -1
console.log(versionCmp("1.19.0.1", "1.2.0.4")); // should be 1
console.log(versionCmp("1.2.3.4", "1.2.3.4")); // should be 0
You could remove all dots and then parse it as an integer.
Take note tho, this solution doesn't work in the long term.

Categories