Skip to content

Commit c6cc5aa

Browse files
Added all remaining JS write ups
1 parent 7c86436 commit c6cc5aa

File tree

69 files changed

+3815
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+3815
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
Codewars. 11/07/20. 'Float to Binary Conversion'. 4kyu. Here we create a function that converts a float (base 10) to IEEE 754 binary in
3+
32 bit single precision. This is the first 4kyu JavaScript kata I have self-solved and the second 4kyu kata I have self-solved in general,
4+
the first being 'Range Extraction' for Ruby. Here is the solution I developed to solve the challenge.
5+
6+
Converting float to IEEE754:
7+
1) An IEEE754 32 bit floating point representation consists of three sections: the sign bit, which is 1 bit; the exponent, which is 8 bits;
8+
and the fraction, which is 23 bits.
9+
2) The process of conversion from float involves a number of steps, the first of these is to convert the float to regular binary.
10+
3) Once the float is in regular binary, we move its decimal point to just after the leftmost 1 bit. Everything after the decimal point in
11+
its new position, will comprise the fraction. For positive numbers, padding with zeros may be required to get the fraction to 23 bits,
12+
for negative numbers, keeping only the first 23 bits may be required because this may be longer than 23 bits.
13+
4) When finding the exponent, we use a bias, which for IEEE754 32-bit is 127, for IEEE754 64 bit double precision, it is 1023. We add the
14+
amount of shifts we did when moving our decimal point after the leftmost 1 bit, to the bias, then convert the produce to regular binary,
15+
if necessary, we pad the start with zeros to make it 8 bits.
16+
5) The easiest thing to find is the sign bit, this is 1 if the float is negative and 0 if the float is positive.
17+
6) We concatenate the sign bit, the exponent and the fraction together.
18+
19+
The Code:
20+
1) We define our function floatToBinaryMS, which takes a number as its argument. The number can be positive or negative and it can be in
21+
string form or number form.
22+
2) As per the process described above, the first thing we do is convert the float to regular binary first by making any string numbers,
23+
a number data type and second by using toString(2) to convert to regular binary.
24+
3) Now we find the sign bit, if the regular binary includes a minus symbol, we make the sign bit 1, if not, we make the sign bit 0.
25+
4) Now we are going to perform our decimal shift, but first, to make our life easier, if the number is positive, we add a decimal point to
26+
the end of binary.
27+
5) Now we create a variable fraction, which is binary with the decimal point deleted, then placed after the first 1 bit in the binary
28+
number.
29+
6) We then find the amount of shifts, by subtracting the index position of the decimal point in fraction (which is after the first 1 bit)
30+
from the index position of the decimal point in binary (which is where it originally was). We store this in a variable shifts.
31+
7) Now we change fraction to its (almost) final form, by first off removing every character up to and including the decimal point. Then we
32+
use the slice method to keep only the first 23 bits, if there are more than 23 bits, which may be the case for negative inputs.
33+
8) We then get the exponent, which is the bias (127) + shifts, converted to regular binary and padded with zeros at the start to make it
34+
8 bits if necessary.
35+
9) We have all the components to create our IEEE754 32 bit binary, so we simply concatenate signBit, exponent and fraction. If our input
36+
was positive, fraction may still not be 23 bits, so we simply pad the end with zeros if this is the case, until we have 32 bits.
37+
*/
38+
39+
function floatToBinaryMS(num) {
40+
let binary = parseFloat(num).toString(2);
41+
let signBit = binary.includes('-') ? 1 : 0;
42+
if (!binary.includes('-')) {binary = binary + '.';}
43+
let fraction = binary.replace(/\./, '').replace(/(?<=1)/, '.');
44+
let shifts = binary.indexOf('.') - fraction.indexOf('.');
45+
fraction = fraction.replace(/^-?[01]+\./, '').slice(0,23);
46+
let exponent = (127 + shifts).toString(2).padStart(8, '0');
47+
return (signBit + exponent + fraction).padEnd(32, '0');
48+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Codewars. 29/08/20. 'Next smaller number with the same digits'. 4kyu. Here we create a function that takes a positive integer and returns
3+
the next smaller integer that can be formed with the same digits. For example, 2071 will return 2017 and 1234567908 will return
4+
1234567890. If a smaller number cannot be formed with the same digits, or the next smaller number would require the leading digit be a zero,
5+
return -1. For example, 135 cannot be turned into a smaller number and 1027 would result in 0721, so -1 is returned. Here is the solution
6+
I developed to solve the challenge.
7+
8+
The Algorithm
9+
1) Starting from the right, find the first number that has at least one smaller number to its right. For example, in 3928555 this will be
10+
8. Let's call this x.
11+
2) Then we find the largest digit that is to the right of x, that is smaller than x. If we have multiple digits that fit this criteria, we
12+
always take the digit closest to x. For example, in 3928555, this will the 5 immediately after 8, i.e. index position 4. We call this y.
13+
3) We swap x and y, which makes the number smaller. For 3928555 we get 3925855.
14+
4) We then sort all digits to the right of y - which is now in the position where x was - in descending order. This makes the number as big
15+
as possible, without making it bigger than the original. For 3928555, which is 3925855 after step 3, remains the same because the digits
16+
are already in descending order.
17+
18+
The Code
19+
1) The first thing we do is convert our number to a string, turn it into an array of characters and then reverse it. We store this in a
20+
variable called arr.
21+
2) We work with the number in reverse so that we don't need to use for loops to iterate backwards.
22+
3) Because we are working with the number in reverse, we find the index position of the first number that has a smaller number to the left
23+
of it. We store this in x.
24+
4) If we traversed the entire number and no number had a number to the left of it that was smaller, this number cannot be turned into a
25+
smaller number with the same digits, so we return -1.
26+
5) Now we are going to look for y. Looking at all the numbers to the left of x, by slicing up to and not including x. We initialize y to
27+
the first number in the slice which is smaller than arr[x]. We find this first smallest to make our checking easier when we look for the
28+
smallest.
29+
6) Now, using forEach to iterate over all the numbers to the left of arr[x], we check on each iteration whether the current digit is less
30+
than arr[x] and whether it is greater than or equal to the current arr[y], if so, y becomes the index position of the current digit.
31+
Using this method, if there are multiple smallest digits before x, y ends up being the one closest to x.
32+
7) Now we swap x and y.
33+
8) Now arr[y] is in the position where arr[x] used to be, so we take a slice of all the numbers to the left of x's original position
34+
(y's new position) and sort them in ascending order - because remember the number is still reversed - and we concatenate this with the
35+
rest of the array from x's original position (y's new position).
36+
9) Now forming the smaller number is complete, we reverse the array of string numbers back and join it into a string. We update this as the
37+
value of n.
38+
10) If our next smaller number - a string currently - starts with a 0, we return -1. If not, we return the integer form of the number.
39+
*/
40+
41+
function nextSmallerMS(n) {
42+
let arr = [...String(n)].reverse();
43+
let x = arr.findIndex((d,i,a) => i > 0 && a[i-1] < d);
44+
if (x === -1) {return -1;}
45+
let y = arr.slice(0,x).findIndex(d => d < arr[x]);
46+
arr.slice(0,x).forEach((d,i) => {
47+
if (d < arr[x] && d >= arr[y]) {y = i;}
48+
});
49+
[arr[x], arr[y]] = [arr[y], arr[x]];
50+
n = arr.slice(0, x).sort((a,b) => a - b).concat(arr.slice(x)).reverse().join('');
51+
return n.startsWith('0') ? -1 : +n;
52+
}
53+
54+
/*
55+
Here is another solution I developed which doesn't reverse the number and instead follows the algorithm more accurately.
56+
1) We first turn the number into an array of string digits, using string interpolation and the spread operator. We store this in a variable
57+
called arr.
58+
2) We initialize a variable called pivot to -1. The pivot is the first number - starting from the right - which has a number to its right
59+
that is smaller.
60+
3) We create a for loop which will start at the penultimate element and then iterate backwards. It will always check the current and the
61+
next element, so the loop must continue while i = 0 but will finish after that.
62+
4) Inside our for loop, if the current element is larger than the next - i.e. has a smaller number to its right - we set the pivot equal
63+
to its index position and break out of the for loop.
64+
5) If pivot is still -1 that means we traversed the entire number and there was no digit which had a smaller digit to its right, thus a
65+
smaller number cannot be formed with the same digits so we return -1.
66+
6) We initialize a variable called afterPiv, which will be the largest digit to the right of the pivot that is smaller than the pivot.
67+
7) We create another for loop, which will start at the last digit of the number, iterate backwards and stop when it gets to the index
68+
pivot.
69+
8) Inside this for loop, if the current element is smaller than the pivot and the current element is greater than or equal to the current
70+
afterPiv, or afterPiv is undefined, afterPiv becomes the index position of the current element.
71+
9) Essentially, as soon as the first digit less than the pivot is found, that digit's index position will become the value of afterPiv. Then
72+
after that, if a digit that is greater than or equal to the digit of afterPiv - and less than the pivot - is found, that digit's index
73+
position will become afterPiv, this ensures that if we have multiple afterPiv's e.g. the 5s in 3928555, the closest 5 will end up being
74+
the settled afterPiv.
75+
10) We then swap the pivot and afterPiv.
76+
11) All the digits to the right of afterPiv's new index position (pivot's original position) get sorted in descending order and merged
77+
with the digits up to and including afterPiv, then we join the array into a string.
78+
12) Our next smallest number is formed into a string, but if it starts with a 0, we return -1, otherwise, we return the integer form of our
79+
next smallest number.
80+
*/
81+
82+
function nextSmallerMSX(n) {
83+
let arr = [...`${n}`];
84+
let pivot = -1;
85+
86+
for (let i = arr.length - 2; i >= 0; i--) {
87+
if (arr[i] > arr[i+1]) {
88+
pivot = i;
89+
break;
90+
}
91+
}
92+
93+
if (pivot === -1) {return -1;}
94+
let afterPiv;
95+
96+
for (let i = arr.length - 1; i > pivot; i--) {
97+
if (arr[i] < arr[pivot] && (arr[i] >= arr[afterPiv] || !afterPiv)) {afterPiv = i;}
98+
}
99+
100+
[arr[pivot], arr[afterPiv]] = [arr[afterPiv], arr[pivot]]
101+
n = arr.slice(0, pivot + 1).concat(arr.slice(pivot + 1).sort((a,b) => b - a)).join('');
102+
return n.startsWith('0') ? -1 : Number(n);
103+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
Codewars. 22/06/20. 'Convert A Hex String To RGB'. 5kyu. When working with colour values it can be sometimes useful to extract the
3+
individual red, green and blue component values for a colour. Here we create a function that accepts a case-insensitive hexadecimal colour
4+
string as its parameter e.g. '#FF9933' and returns an object with the structure {r: 255, g: 153, b: 51} where r, g and b range from
5+
0 through 255. The function does not need to support the shorthand form of hexadecimal notation i.e. '#FFF'. Here is the solution I
6+
developed to solve the challenge. This is the first 5kyu kata I've solved in JavaScript.
7+
1) We define our function hexToRGBMS, which takes a hex string as its argument.
8+
2) We first split the hex string into it's component colour parts by using the match method and creating an array of every two word
9+
characters, thus the hash symbol at the start will be ignored.
10+
3) We then map over the array of hex colour components and convert them to decimal using the parseInt method. We pass 16 into the second
11+
(radix) parameter to specify that we are converting the string from hex to decimal.
12+
4) We then return the object of our colour components.
13+
*/
14+
15+
function hexToRGBMS(h) {
16+
h = h.match(/\w\w/g);
17+
h = h.map((c) => parseInt(c, 16));
18+
return {r: h[0], g: h[1], b: h[2]};
19+
}
20+
21+
/*
22+
Here is a one-line solution, which uses the parseInt method of conversion.
23+
1) Inside an object, we make each key the colour component, and each value the decimal representation of the hex substring.
24+
2) We use the slice method to extract each colour component from the hex string.
25+
*/
26+
27+
function hexToRGB(h) {
28+
return {r: parseInt(h.slice(1,3), 16), g: parseInt(h.slice(3,5), 16), b: parseInt(h.slice(5,7), 16)}
29+
}
30+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
Codewars. 14/07/20. 'Formatting a number as price'. 5kyu. Here we create a function that takes a number and converts it to a price format.
3+
Every 3 numbers from right to left from the decimal point should have a comma seperating them. Cents should have 2 decimal characters, as in
4+
any price. For example, 13253.5123 should return '13,253.51'. Here is the solution I developed to solve the challenge.
5+
1) We define our function numberToPriceMS, which takes a number as an argument.
6+
2) First we handle our error checking, we our input is a string, we return 'NaN'.
7+
3) We make num a string so we can perform our parsing.
8+
4) We create a variable called negative, which we initially set to false.
9+
5) If our number includes a minus symbol, we set negative equal to true.
10+
6) Now we check if our input number doesn't contain a decimal point and cents, if so, we add a decimal point and 00 cents to num.
11+
7) Now we make the cents portion of our input, by calling replace on num and deleting all characters apart from the decimal and the numbers
12+
after it. Then for the cases where cents is currently .1 or .5, we add a 0. But we also may have cases which were .129, which will now
13+
be .1290, we use the slice method to keep only the first 3 characters, so in this case that will be .12.
14+
8) Now we set dollars equal to the decimal and numbers after it deleted from num, so we only have the numbers before the decimal point.
15+
9) If dollars contains 3 or less digits, it won't need any commas, so we return dollars + cents.
16+
10) Finally, we perform our comma formatting. We split dollars into an array of characters, reverse all the characters, then join it back
17+
into a string. We then call the match method generating an array of 3 digits and then when it cannot be 3 digits, 1 or 2 digits. We
18+
join this array into a string delimited by commas, so now our commas are in place. Now we split into an array of characters again,
19+
reverse the array and join it back into a string.
20+
11) If negative is true, we return dollars and cents with a minus symbol at the front, if not, we return dollars and cents.
21+
*/
22+
23+
function numberToPriceMS(num) {
24+
if (typeof num === 'string') {return 'NaN';}
25+
num = String(num);
26+
let negative = false;
27+
if (num.includes('-')) {negative = true;}
28+
if ((/^-?\d+$/).test(num)) {num = num + '.00';}
29+
let cents = (num.replace(/.+(?=\.\d+)/, '') + '0').slice(0, 3);
30+
let dollars = num.replace(/(?<=\d+)\.\d+/, '');
31+
if (dollars.match(/\d/g).length < 4) {return dollars + cents;}
32+
dollars = [...dollars].reverse().join('').match(/\d{1,3}/g).join(',').split('').reverse('').join('');
33+
return negative ? '-' + dollars + cents : dollars + cents;
34+
}
35+
36+
/*
37+
Here is a very clever solution that uses no regular expressions, submitted by a Codewars user.
38+
1) We use the isNaN method to check if the input is not a number, this doesn't work if passed an empty string so we also check is the
39+
input is an empty string, if so, we return NaN as a string.
40+
2) We create a variable called sign, if num is a negative number, the sign is a minus symbol, if not, sign is an empty string.
41+
3) Now we set num equal to its absolute value, then we use toFixed method. To toFixed method converts a number to a string while rounding
42+
it to a specified number of decimals. Since the longest decimals in our tests is 3 (.129), we round to 3 decimal places, which returns
43+
the same in this case. But for cases where num had .1 or no decimals at all, we now have .100 or .000.
44+
4) We use the slice method to delete the last character from num, now our number has 2 decimals.
45+
5) We split num into an array of characters because we are about to add in our commas.
46+
6) We create a for loop where we will add in our commas. We set i equal to 6 places from the end of num, so the first place our comma will
47+
go is past our decimals and decimal point, and past the last 3 dollar digits i.e. from right to left, the first 3 dollar digits from
48+
the decimal point. Our for loop runs as long as i is greater than 0. So for example, if num at this point is '-5.00', the for loop won't
49+
even run because there are not enough elements. On each iteration, i decrements by 3.
50+
7) On each iteration of our for loop, we use the splice method to add commas to our num array of characters.
51+
8) We return sign concatenated to the front of num joined back into a string.
52+
*/
53+
54+
function numberToPrice(num) {
55+
if (isNaN(num) || num === '') {return String(NaN);}
56+
let sign = num < 0 ? '-' : '';
57+
num = Math.abs(num).toFixed(3).slice(0,-1).split('');
58+
for (let i = num.length - 6; i > 0; i -= 3) {
59+
num.splice(i, 0, ',');
60+
}
61+
return sign + num.join('');
62+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
Codewars. 19/08/20. 'Number of trailing zeros of N!' 5kyu. Here we create a function which calculates the number of trailing zeros in the
3+
factorial of a given number n. The factorial of a number is simply the product of all positive integers less than or equal to n. For
4+
example, 5! = 1 * 2 * 3 * 4 * 5 = 120.
5+
6+
The Method/Rule:
7+
Any number greater than 4! ends in one or more zeros. In order to calculate the number of trailing zeros in a given factorial, we simply
8+
have to successively divide that number by 5 until that number is less than 5. How ever many times n can be successively divided by 5, is
9+
the number of trailing zeros of n!. For example, 30 / 5 = 6, then 6 / 5 = 1, so there are 7 trailing zeros in 30!. 30! is
10+
265252859812191058636308480000000 so this is correct.
11+
12+
The Code:
13+
1) We create a variable called trailingZeros and initialize it to 0.
14+
2) We create a while loop which runs as long as n is greater than or equal to 5.
15+
3) We make n equal to n divided by 5 and floor the result, ceiling the result didn't work.
16+
4) Each time we divide n by 5, we increment trailingZeros by the result.
17+
5) Once n is lower than 5, the while loop is broken out of, and we return trailingZeros.
18+
*/
19+
20+
function zerosMS(n) {
21+
let trailingZeros = 0;
22+
while (n >= 5) {
23+
n = Math.floor(n / 5);
24+
trailingZeros += n;
25+
}
26+
return trailingZeros;
27+
}

0 commit comments

Comments
 (0)