Code Katas #5 - Solving Code Wars Katas and Talking Through My Process

preview_player
Показать описание
Show starts at 2:34
Рекомендации по теме
Комментарии
Автор

You're quite well versed in javascript, CJ!
You're now one of my biggest inspirations!
Programming is fun!

WladyslawKozharin
Автор

PART 1/2

hey cj, :)
here are my attempts at solving the same katas that you solved in this video.
thanks a lot for finding time to make these. ;) i can really feel like they're sharpeningmy coding skills!

** kata #1: sum of two lowest positive integers
* note: kata didn't say anything about the possible occurences of nonpositive numbers in the array, so i didn't assume that they won't. function accepts arrays of any length. i also generalized it to work for any number of natural numbers.

const findSumOfNSmallestNaturalsIn = (array, N=2) => {
const L = array.length;
const naturals = [];
let n = 0;
let sum = 0;
let idx = 0;
while (idx < L && n < N) {
const int = array[idx];
if (int > 0) {
let atIdx = 0;
while (atIdx < n && naturals[atIdx] < int) atIdx++;
naturals.splice(atIdx, 0, int);
n++;
sum += int;
}
idx++;
}
if (n < N) {
sum = undefined;
} else {
for (let i=idx; i<L; i++) {
const int = array[i];
const biggestNat = naturals[n-1];
if (int > 0 && int < biggestNat) {
sum -= (biggestNat - int);
let atIdx = 0;
while (naturals[atIdx] < int) atIdx++;
naturals.splice(atIdx, 0, int);
naturals.pop();
}
}
}
return sum;
}

* my attempt's explanation:
i traverse through the array to find N natural numbers.
i keep them always in an ascending order as i collect them.
i also update their sum.
if i won't find all N of them, i return undefined as the value of the sum.
otherwise, starting from the index at which i finished in point one i traverse further through the array to find more smaller natural numbers.
whenever i do, i update the sum, i put it in my collection in such a way, that it remains in ascending order, and i get rid of the biggest natural number in that collection.
i return the result.

** kata #2: credit card mask

const maskify = (message, UNMASKED=4) => {
const LENGTH = message.length;
const MASKED = Math.max(0, LENGTH - UNMASKED);
return "#".repeat(MASKED) + message.slice(MASKED);
}

* my attempt's explanation:
i calculate the length of the masked part.
i return a new string that is a concatenation of this many hashes and a part of the message that should come after it.

** kata #3: creat phone number

const creatUSPhoneNumberFrom = (array) => {

const L = array.length;
if (L !== 10) {
throw `Expecting 10 elements: ${L} given.`;
}
const onlyDigits = array.every((elem) => (
Number.isInteger(elem) && -1 < elem && elem < 10
));
if (onlyDigits === false) {
throw "Expecting 10 digits: nondigit found.";
}
const digits = array.join("");
const NPA = digits.slice(0, 3);
const NXX = digits.slice(3, 6);
const XXXX = digits.slice(6);
return `(${NPA}) ${NXX}-${XXXX}`;
}

* my attempt's explanation:
i check whether the array indeed contains 10 digits exclusively.
i slice it into parts and stitch it back together in the right formatting.

** kata #4: equal sides of an array

const findMiddleGroundOf = (array) => {
const L = array.length;
let [lSum, rSum] = [0, 0];
for (let i = 1; i < L; i++) rSum += array[i];
let idx = 0;
while (idx < L && lSum !== rSum) {
idx++;
lSum += array[idx-1];
rSum -= array[idx];
}
if (idx === L) return -1;
return idx;
}

* my attempt's explanation:
i initialize the left sum to be 0 and the right sum to be the sum of all elements in the array except for the first one.
i assume the searched index (middle ground) to be zero.
for as long as this index is smaller than the length of the array and the left sum differs from the righ sum, i increment the index, i add to the left sum the element with the previous index, i subtract from th eright sum the element with the current index.
if the index is equal to the length of the array (this includes 0 as well), i return -1.
otherwise i return the index.

michalbotor
Автор

Deep Divers - start at 4:20 and go until 14:10 - this guy is awesome

estebanmartinez
Автор

1:31:13 you made me google it! Number Palindromes are evenly divisible by either 3 or 11, depending on whether they are an even or odd number of digits. So "555" is divisible by 3 and "5555" is divisible by 11

ChrisGrazioli
Автор

1:39:12 Mathematically you get an infinite loop because it does not matter how many times you divide a positive integer by 10 you still get a positive integer and never 0

(Im not sure but I think that at some point JS will approximate it to 0)

danielescotece
Автор

Oh god ! Where is the whiteboard ? <3

louptreize
Автор

PART 2/2

** kata #5: palindrome chain length
* note: due to the fact that there are numbers like 196, which palindrome distance has not yet been found and might not even exist, maximum allowable number of iterations has been set, feel free to change it however. also, since the numbers obtained during search are getting pretty big pretty fast, this function expects numbers to be given in a string format for it uses a digit by digit addition with carrying which i coded first for your 'code katas #4' video. therein you can find its explanation if you wish.

const palindromeDistOf = (number, MAX_ITER = 100) => {

if (typeof number !== "string") {
throw `Please enter a number in a string format.`;
}

if (/^\d+$/.test(number) === false) {
throw "Please enter a positive integer in a string format.";
}

const trimExcessiveLeadingZerosIn = (number) => {
const L = number.length;
let idx = 0;
while (idx < L - 1 && number[idx] === "0") idx++;
return number.slice(idx);
}

const isPalindrome = (number) => {
const NUM_DIGITS = number.length;
const HALF_NUM_DIGITS = Math.floor(NUM_DIGITS / 2);
let isPalindrome = true;
for (let idx = 0; idx < HALF_NUM_DIGITS; idx++) {
if (number[idx] !== number[NUM_DIGITS - 1 - idx]) {
isPalindrome = false;
break;
}
}
return isPalindrome;
}

const reverseString = (string) => {
const L = string.length;
let reversed = "";
for (let idx = L - 1; idx >= 0; idx--) {
reversed += string[idx];
}
return reversed;
}

// function written first for the 'code katas #4'
const sumStrings = (strA, strB) => {
const [A_L, B_L] = [strA.length, strB.length];
const L = Math.max(A_L, B_L);
if (A_L < L) strA = "0".repeat(L - A_L) + strA;
if (B_L < L) strB = "0".repeat(L - B_L) + strB;
let strAB = "";
let carrying = 0;
for (let i = L - 1; i >= 0; i--) {
const sum = Number(strA[i]) + Number(strB[i]) + carrying;
const digit = sum % 10;
strAB = String(digit) + strAB;
carrying = (sum - digit) / 10;
}
if (carrying > 0) strAB = carrying + strAB;
return strAB;
}

let palindromeDist = 0;
let nextNumber =
while (isPalindrome(nextNumber) === false && palindromeDist < MAX_ITER) {
const txenNumber = reverseString(nextNumber);
nextNumber = sumStrings(nextNumber, txenNumber);
palindromeDist++;
}
if (palindromeDist === MAX_ITER) {
throw `Number ${number} reached maximum number of iterations, ${MAX_ITER}.`;
}
return palindromeDist;
}

* my attempt's explanation:
i check whether the entered number is a positive integer in a string format.
i define a helper function that will trim excessive leading zeros in a number, so "0000" will become "0" and "011" will become "11", etc. if i didn't then a number like "09" would give me an incorrect palindrome length of 1 instead of the correct one, 2.
i define a helper function that will determine whether a given number is a palindrome. it does so by checking whether every next digit on the left is equal to every, corresponding to it, previous digit on the right.
i define a function that will reverse a given string (screw you js for not having this string method implemented natively!).
finally i define a function that given two numbers in a string format returns their sum in a string format (again, for its explanation, see my comment under 'code katas #4' video).
i assume the palindrome distance to be zero.
i trim any excessive leading zeros in the original number.
for as long as the number is not a palindrome and the maximum allowable number of iterations has not been reached, i create a new number that is a sum of the previous number and the reversal of the previous number and i increase palindrome distance by one.
if the maximum allowable number of iterations has been reached i throw an error, otherwise i return the palindrome distance of the original number.

** kata #6: roman numerals encoder

const romanNotationOf = (number) => {

if (number < 1 || number > 3999) {
throw `Expected a number between 1 and 3999, got ${number} instead.`;
}

const romanSymbolOf = {
'1': 'I', '5': 'V',
'10': 'X', '50': 'L',
'100': 'C', '500': 'D',
'1000': 'M'
};

const romanLogicOf = {
'1': ['1'],
'2': ['1', '1'],
'3': ['1', '1', '1'],
'4': ['1', '5'],
'5': ['5'],
'6': ['5', '1'],
'7': ['5', '1', '1'],
'8': ['5', '1', '1', '1'],
'9': ['1', '10']
};

const decimalNotation = number.toString();
const L = decimalNotation.length;
let romanNotation = "";
for (let idx = 0; idx < L; idx++) {
const digit = decimalNotation[idx];
if (digit === '0') continue;

const pos = L - 1 - idx;
for (const subDigit of romanLogicOf[digit]) {
const subNumber = String(eval(`${subDigit} * Math.pow(10, ${pos})`));
const symbol = romanSymbolOf[subNumber];
romanNotation += symbol;
}
}
return romanNotation;
}

* my attempt's explanation:
since, as far as i know, romans used neither zero nor negative numbers and they didn't go over 3999 (?), i check whether the entered number is between 1 and 3999.
i associate a roman symbol with every next decuple of 1 and 5 between 1 and 1000.
i associate every positive digit with a list of numbers representing the logic of how this digit is understood in the roman numeral system.
i create a decimal notation of the number.
i initialize the roman notation of the number to be empty.
for every digit in a decimal notation of the number: if its zero i skip it, if it's not, i determine its position (3 means thousands, 2 means hundreds, 1 means tens, 0 means ones), i create a list of numbers representing the logic of how this digit is understood in the roman numeral system. for every number in that list: i create a new number from it that takes into account the position of the digit based on which it was created, i find a symbol associated with that new number, and i add it to the roman notation of the number.
i return the roman notation of the number.

cheers!

michalbotor
Автор

try finding the palindrome chain length of 196.
good luck! ;p

did anyone actually prove that this palindrome chain length is finite for all natural numbers?

oh.. it's an open problem:
that's why i didn't find anything after reaching 20, 000 iterations.. ;p

michalbotor
Автор

1:59:00 please no... almost unsubscribed... :D

mtt_