Last active
June 29, 2023 15:28
-
-
Save LGitHub-sprout/e692455d8b52344814142a4bc808aab2 to your computer and use it in GitHub Desktop.
TOP Foundations Exercises #8-12
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://www.theodinproject.com/lessons/foundations-fundamentals-part-5#assignment | |
// Calculator bits and pieces | |
// 1. The calculator functions | |
const add = (a, b) => a += b; | |
const subtract = (a, b) => a -= b; | |
const multiply = (a, b) => a *= b; | |
const divide = (a, b) => a /= b; | |
function operate(operator, num1, num2) { // still needs the operators | |
if (operator === '+') { | |
return add(num1, num2); | |
} | |
if (operator === '-') { | |
return subtract(num1, num2); | |
} | |
if (operator === '*') { | |
return multiply(num1, num2); | |
} | |
if (operator === '/') { | |
return divide(num1, num2); | |
} | |
return operator; | |
// takes an operator and 2 nums | |
// then calls one of the above functions on the nums. | |
}; | |
// console.log(operate('+', 6, 4)); console.log(operate('-', 6, 1)); console.log(operate('*', 3, 4)); console.log(operate('/', 3, 4)); | |
// Using a constructor | |
function Calculator(a, b, operator, element) { | |
this.a = 0; | |
this.b = 0; | |
this.operator = ['+', '-', '*', '/']; | |
this.add = function (a, b) { return a += b; }; | |
// Display receives click/keypress value & shows on screen | |
// Also builds equation string for operations stack | |
// https://stackoverflow.com/questions/12731528/adding-event-listeners-in-constructor | |
// https://www.section.io/engineering-education/keyboard-events-in-javascript/#handling-keyboard-events-in-javascript | |
const display = document.querySelector('.calc-display-wrap'); // console.log(display) | |
display.textContent = 'poop'; | |
// this.element = document.querySelector('.calc-display-wrap'); | |
const self = this; | |
this.bar = function (event, element) { | |
// console.log(event); | |
// return event; // no need to return event? | |
}; | |
// window.addEventListener('keypress', // keydown | |
// function (event, element) { | |
// display.textContent += `${event.key}`; | |
// // console.log(display); // this.element is undefined, | |
// // console.log(event.clientY, event.clientX); // event | |
// // event.preventDefault(); | |
// // self.bar(event.clientX); // seems to do nothing | |
// } | |
// ); | |
}; | |
// const calc = new Calculator('.calc-display-wrap'); | |
// calc; // works, but bar() doesn't do anything | |
// // Display receives click/keypress value & shows on screen | |
// // Also builds equation string for operations stack | |
// // https://stackoverflow.com/questions/12731528/adding-event-listeners-in-constructor | |
// this.element = document.querySelector('.calc-display-wrap'); | |
// const self = this; | |
// this.bar = function (event, element) { | |
// // console.log(event); | |
// // return event; // no need ot return event? | |
// }; | |
// this.element.addEventListener('click', // keydown | |
// function (event, element) { | |
// console.log(this.element); // undefined | |
// // self.bar(event.clientX); | |
// console.log(event.clientY, event.clientX); // event | |
// event.preventDefault(); | |
// }); | |
// }; | |
// const calc = new Calculator('.calc-display-wrap'); | |
// calc.bar(display); | |
// const calc = new Calculator(); | |
// console.log(calc.add(21, 34)); // 55 | |
// console.log(calc.operator.includes('*')); // true | |
// console.log(calc.operator.filter(o => o === '*').join()); // string | |
// console.log(calc.operator.find(e => e === '/')); // works | |
// https://www.geeksforgeeks.org/how-to-create-dynamic-length-array-with-numbers-and-sum-the-numbers-using-javascript/ | |
// operate() using reduce() | |
let input = '1000 - 5000'; | |
// would need display to a space after 1st num and operator | |
const getInputArray = function (str) { | |
return str.split(' '); // .map(Number); | |
}; | |
// It makes sense to pull out the indiv nums and operator early | |
const operate2 = function () { | |
const inputArr = getInputArray(input); console.log(inputArr); // (3) ['699', '-', '9156987'] | |
if (inputArr.includes('-')) { | |
// I need a variable for the operator to pass as param for display | |
// also need the actual arithmetic operator for expression | |
const operator = inputArr.indexOf('-'); console.log(operator) | |
return inputArr.toSpliced(operator, 1).reduce((acc, currVal, i, a) => { | |
//currVal -= acc; // 1000 wrong | |
acc -= currVal; | |
// currVal = +currVal; | |
console.log('value', currVal, acc) | |
// acc -= currVal; // Wrong! 0 - 1000 = -1000 | |
return acc; | |
}); //, 0); | |
} | |
return getInputArray(input); | |
}; | |
// console.log(operate2()); | |
/* | |
Remember that I need vars for ea operand & operator for the display. | |
I have an array to loop over | |
if array contains includes specific operator | |
slice splice, then reduce? | |
*/ | |
// Display | |
const display = document.querySelector('.calc-display-wrap'); // console.log(display) | |
const para = document.createElement('p'); | |
// display.append(para); // .setAttribute('class', 'poop'); | |
// const display = document.getElementsByClassName('display'); console.log(typeof Array.from(display)); | |
display.setAttribute('style', 'border:solid 1px #7f7f7f; height:2em; text-align:center;'); | |
// const key = document.querySelector('.key'); console.log(key); // works | |
function printToDisplay(e) { | |
// console.log(e.target.tagName, Array.from(e.target.classList).includes('display')); | |
// console.log('e', e.key, typeof e.key, e.currentTarget, e.target.tagName); // .key is the value, target is element? | |
// question is how to target the child of display-wrap | |
const str = e.key; | |
const code = e.code.charAt(0); // Numpad1 thru Numpad0 | |
// console.log(typeof key, key, e.key, typeof str, e.type); // string, key value '1', '2', etc. | |
// console.log(e.code, str); // typeof object typeof e, e, | |
// overflow: hidden; https://stackoverflow.com/questions/1165497/how-to-prevent-text-from-overflowing-in-css | |
if (e.key === 'Clear') display.textContent = ''; | |
// the problem is to add spaces to the operator | |
// console.log(str.split()); // string to array | |
if (code === 'N' && e.key !== 'Clear') display.textContent += str; // prints number to the display | |
if (e.key === 'Enter' || e.key === '=') display.textContent = calc.add(a, b); // works, but needs (a, b) vars | |
// if (key === 'Clear') display.textContent = str; // nope | |
// const key = document.querySelector(`div[data-key="${e.key}"]`); | |
}; | |
document.addEventListener('keydown', printToDisplay); // document or window works | |
// 12. Find The Oldest | |
/* Some resources I found while working on this problem: | |
https://www.google.com/search?q=return+product+of+nested+objects+without+mutation+javascript&oq=return+product+of+nested+objects+without+mutation+javascript+&aqs=chrome..69i57.41064j0j7&sourceid=chrome&ie=UTF-8#ip=1 | |
https://dev.to/krsgrnt/safely-copying-nested-objects-in-javascript-5fpi | |
https://www.amitmerchant.com/reduce-array-of-objects-to-an-object-in-javascript/#:~:text=reduce()%20method%2C%20we%20can,wanted%20as%20an%20end%20result. | |
https://www.redbitdev.com/post/using-array-reduce-with-objects | |
https://stackoverflow.com/questions/40025718/es6-finding-data-in-nested-arrays | |
*/ | |
/* | |
@toby Pass obj properties as args | |
Given an object with possible fields | |
(yearOfBrith and yearOfDeath may or may not exist) | |
take the data and return an age. | |
Just one object, one function, no mutation, no reduce. | |
*/ | |
const person = { | |
name: 'Toby', | |
// yearOfBirth: 1969, | |
yearOfDeath: 2088, | |
}; | |
/* | |
Getting the idea: it's helper function that returns age, passes properties if missing. | |
Use getCurrentAge() to return ages for comparison in findTheOldes() | |
*/ | |
const getCurrentAge = ({ | |
yearOfBirth = new Date().getFullYear(), | |
yearOfDeath = new Date().getFullYear() | |
}) => yearOfDeath - yearOfBirth; | |
// console.log('tobys getCurrentAge', getCurrentAge(person)); // 119, 54 or 65 depending which props are missing. | |
// Odin Solution | |
// I want calcAge() to return the product of subtracting death from birth to get ea person's age. | |
// If 'death' doesn't exist, use the new Date() to get the current year. | |
// The findTheOldest() uses vars created using calcAge() to compare which person is eldest. | |
const calcAge = (death, birth) => { | |
if (!death) { | |
death = new Date().getFullYear(); | |
} | |
return death - birth; | |
}; | |
// console.log('calcAge', calcAge(null, 1966)); | |
const findTheOldest2 = function (arr) { | |
// looking for oldest so name accumulator 'eldest' | |
return arr.reduce((eldest, currVal) => { | |
// use calcAge() to initialize | |
eldestAge = calcAge(eldest.yearOfDeath, eldest.yearOfBirth); | |
currValAge = calcAge(currVal.yearOfDeath, currVal.yearOfBirth) | |
// notice when compared like this: 'eldestAge > currValAge ? eldest : currVal' it doesn't work. | |
return eldestAge < currValAge ? currVal : eldest; | |
}); | |
}; | |
// My final working version. | |
const findTheOldest = function (arr, currY = new Date().getFullYear()) { | |
return arr.reduce((acc, currVal) => { | |
if ('yearOfDeath' in acc === false && currY - acc.yearOfBirth > currVal.yearOfDeath - currVal.yearOfBirth) return acc; | |
return acc = acc.yearOfDeath - acc.yearOfBirth > currVal.yearOfDeath - currVal.yearOfBirth ? acc : currVal; | |
}); | |
}; | |
// Duh! Just pass current year as an arg :| | |
const findTheOldest = function (arr, currY = new Date().getFullYear()) { | |
return arr.reduce((acc, currVal) => { | |
if ('yearOfDeath' in acc === false) { | |
if (currY - acc.yearOfBirth > currVal.yearOfDeath - currVal.yearOfBirth) return acc; | |
} | |
return acc = acc.yearOfDeath - acc.yearOfBirth > currVal.yearOfDeath - currVal.yearOfBirth ? acc : currVal; | |
}); | |
}; | |
// Using Object.assign() stops mutation | |
const findTheOldest = function (arr) { | |
return arr.reduce((acc, currVal) => { | |
if ('yearOfDeath' in acc === false) { | |
const target = { yearOfDeath: new Date().getFullYear() }; | |
Object.assign(target, acc) | |
if (target.yearOfDeath - acc.yearOfBirth > currVal.yearOfDeath - currVal.yearOfBirth) return acc; | |
} | |
if (acc.yearOfDeath - acc.yearOfBirth > currVal.yearOfDeath - currVal.yearOfBirth) return acc; | |
return currVal; | |
}); | |
}; | |
// Passes tests but mutates array | |
const findTheOldest = function (arr) { // didn't work [{}, ...arr] | |
const currYear = new Date(); | |
return arr.reduce((acc, currVal, index, theArr) => { | |
if ('yearOfDeath' in acc === false) { | |
acc['yearOfDeath'] = currYear.getFullYear(); | |
} | |
if (acc.yearOfDeath - acc.yearOfBirth > currVal.yearOfDeath - currVal.yearOfBirth) { | |
if ('yearOfDeath' in acc === false) console.log('AFTER: caught it?', acc); // Nothing for 'true' 'false' or 'undefined' | |
return acc; // Removing return on 'acc' returns last item ('Jane') | |
} | |
return currVal; | |
}); | |
} | |
// 11. Get The Titles | |
const getTheTitles = function (arr) { | |
return arr.reduce((acc, currentVal) => { | |
// console.log('currentVal', currentVal, typeof currentVal, Array.isArray(currentVal)) | |
// console.log(currentVal.title, typeof currentVal.title) | |
acc.push(currentVal.title) | |
// for (title of currentVal.title) { | |
// acc.push(title) | |
// } | |
return acc; | |
}, []); | |
}; | |
console.log('getTheTitles', getTheTitles(books)); // getTheTitles(books)).toEqual( ['Book','Book2'] ) | |
// Fibonacci v.2 | |
// https://www.freecodecamp.org/news/array-map-tutorial/ | |
const oldArray = [33, 20, 10, 5]; | |
const newArray = oldArray.map((currentVal, index, arr) => { | |
let nextItem = index + 1 < arr.length ? arr[index + 1] : 0 | |
return currentVal - nextItem; | |
}); | |
// console.log(newArray); // [13, 10, 5, 5] | |
const fibonacci2 = function (n) { | |
// Problem is how I'm constructing initial array | |
// const series = [...Array(n).keys()]; | |
const series = [0, 1, 1, 2]; | |
console.log('series', series); | |
const result = series.map((el, index, arr) => { | |
let nextItem = index + 1 < n ? arr[index + 1] : 0; | |
return el + nextItem; // wrong: doubles el | |
return el + arr[index]; // wrong: doubles el | |
// return el = arr[index] + arr[index + 1]; // wrong: add 2 to ea element | |
// return el + arr[nextItem]; // wrong: both nextItem and arr[nextItem] stil adds 2 to ea el | |
}); | |
console.log('result', result); | |
return result[n]; // must subtract 1 to get last element | |
}; | |
// console.log('fibonacci2', fibonacci2(6)); // (6) .tobe 8 | |
// Fibonacci | |
// https://www.tutorialspoint.com/adding-two-values-at-a-time-from-an-array-javascript | |
const fibonacci = function(n) { | |
n = Number(n); | |
if (n < 0) return 'OOPS'; | |
const arr = [0, 1]; | |
for (let i = 0; i < n; i++) { | |
arr.push(arr[i] + arr[i + 1]); | |
} | |
return arr[n]; | |
}; | |
// // Palindromes v.2 & v.3 w RegEx examples | |
// const spaceRE = /\s+/g; | |
// const digitRE = /\d+/g; | |
// const alphaAZ = /([a-z])/g; // /([a-z])/g; /([a-z])\w+/g; | |
// punctRE = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]/g; | |
const palindromes = function (str) { | |
str = str.toLowerCase(); | |
const extractedStr = str.match(/([a-z])/g); | |
const strMatch = [...extractedStr].join(''); // compare w strReverse for equality | |
// let strReverse = []; | |
let strReverse = ''; | |
for (let i = extractedStr.length - 1; i >= 0; i--) { | |
strReverse += extractedStr[i]; | |
} | |
// for (let i = extractedStr.length; i >= 0; i--) { | |
// strReverse.push(extractedStr[i]); | |
// } | |
// return strReverse = strReverse.join('') === strMatch ? true : false; | |
return strReverse = strReverse === strMatch ? true : false; | |
}; | |
// Panindromes | |
const palindromes = function (str) { | |
const spaceRE = /\s+/g; | |
const digitRE = /\d+/g; | |
punctRE = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]/g; | |
const newStr = str.replace(spaceRE, '').replace(digitRE, '').replace(punctRE, '').toLowerCase(); | |
const reverseStr = [...newStr].reverse().join(''); | |
return newStr === reverseStr; | |
}; | |
// Factorial https://www.thoughtco.com/why-does-zero-factorial-equal-one-3126598 | |
// Khan Academy Factorial https://www.khanacademy.org/math/precalculus/x9e81a4f98389efdf:prob-comb/x9e81a4f98389efdf:combinatorics-precalc/v/factorial-and-counting-seat-arrangements | |
// console.log(5 * 4 * 3 * 2 * 1); // factorial 5 or 5! s/b 120 | |
// TOP recursive example - no range or loop necessary | |
const factorial4 = function (num) { | |
if (num === 0) return 1; | |
return num * factorial4(num - 1); | |
}; | |
console.log(factorial4(10)); // 120 | |
// my factorial loop solution | |
const factorial3 = function (num) { | |
let product = 1; | |
for (let i = num; i > 0; i--) { | |
product *= i; | |
} | |
return product; | |
}; | |
// console.log(factorial3(10)); // 3628800 | |
/* range() | |
It seems I'll need to create a range for factorial. | |
But I need it to go from start to zero (or 1, I suppose). | |
Functional Programming Recursive Range Solution | |
https://dev.to/ycmjason/how-to-create-range-in-javascript-539i | |
*/ | |
// function recursiveRange (start, end) { | |
// if (start === end) return [start]; | |
// // recursive case | |
// return [start, ...recursiveRange(start + 1, end)]; | |
// } | |
// console.log(recursiveRange(3, 13)); // [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] | |
const loopRange = (start = 0) => { | |
const startArr = [start]; | |
if (startArr.includes(0)) return 1; | |
let end = start - 1; | |
for (start; end > 0; end--) startArr.push(end); | |
const factorial = startArr.reduce((acc, currentVal) => { | |
// console.log(currentVal, start); | |
return start *= currentVal; | |
}); | |
return factorial; | |
}; | |
console.log('loopRange', loopRange(19)); // 5! = 120, 10! = 3628800 | |
// raises one number to the power of another number | |
const power = function (num, pow) { | |
let total = 1; | |
for (let i = 1; i <= pow; i++) { | |
total *= num; | |
} | |
return total; | |
}; | |
// console.log(7 * 7 * 7 * 7 * 7 * 7 * 7 * 7, 'manual 7pow8'); // 5764801 | |
// console.log(power(7, 8), '7pow8'); // 5764801 | |
const power3 = function (base, pow) { | |
return arr = [...Array(pow).fill(base)].reduce((acc, currentVal) => acc * currentVal); | |
}; | |
console.log(power3(4, 3)); // 64 | |
console.log(4 * 4 * 4); // 64 | |
console.log(power3(6, 2)); // 36 | |
console.log(power3(6, 9)); // 10077696 | |
console.log(power3(7, 8)); // 5764801 | |
console.log(7 * 7 * 7 * 7 * 7 * 7 * 7 * 7, 'manual 7 to power of 8'); // 5764801 | |
const multiplyNums = [2, 4, 6, 8, 10, 12, 14]; // [2, 4, 6, 8, 10, 12, 14] | |
const multiply = [...multiplyNums].reduce((acc, nextNum) => { | |
return acc *= nextNum; | |
}); | |
// console.log('multipy', multiply); // 645120 | |
const sum = function (arr) { | |
return arr.reduce((acc, currentVal) => { | |
return acc += currentVal; | |
}, 0, | |
); | |
}; | |
console.log(sum([1,3,5,7,9])); // 25 | |
const sumNums = [1, 3, 5, 7, 9]; | |
const sum = [...sumNums].reduce((acc, nextNum) => { | |
return acc += nextNum; | |
}, 0); | |
// console.log('sum', sum); // s/b 25 | |
const sumLoop = (arr) => { | |
let total = 0; | |
for (let i = 0; i < arr.length; i++) { | |
// console.log(arr[i]); | |
// total = total + arr[i]; | |
total += arr[i]; | |
} | |
return total; | |
}; | |
// console.log('sumLoop', sumLoop(sumNums)); // 25 | |
const add = function (num1, ...theArgs) { | |
for (let num2 of theArgs) return num1 += num2; | |
}; | |
// console.log(add(2, 6)); // 8 | |
const subtract = function (num1, ...theArgs) { // ...theArgs is an array, therefore: loop | |
for (let num of theArgs) { | |
num1 -= num; | |
} | |
return num1; | |
}; | |
// console.log(subtract(10, 4, 12, 11, 9, 6, 19, 4)); // 6 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment