diff --git a/src/01-strings-tasks.js b/src/01-strings-tasks.js index afc97fa6b7..1354696d31 100644 --- a/src/01-strings-tasks.js +++ b/src/01-strings-tasks.js @@ -18,8 +18,8 @@ * 'aa','' => 'aa' * '', 'bb' => 'bb' */ -function concatenateStrings(/* value1, value2 */) { - throw new Error('Not implemented'); +function concatenateStrings(value1, value2) { + return value1 + value2; } @@ -34,8 +34,8 @@ function concatenateStrings(/* value1, value2 */) { * 'b' => 1 * '' => 0 */ -function getStringLength(/* value */) { - throw new Error('Not implemented'); +function getStringLength(value) { + return value.length; } /** @@ -51,8 +51,8 @@ function getStringLength(/* value */) { * 'John','Doe' => 'Hello, John Doe!' * 'Chuck','Norris' => 'Hello, Chuck Norris!' */ -function getStringFromTemplate(/* firstName, lastName */) { - throw new Error('Not implemented'); +function getStringFromTemplate(firstName, lastName) { + return `Hello, ${firstName} ${lastName}!`; } /** @@ -65,8 +65,8 @@ function getStringFromTemplate(/* firstName, lastName */) { * 'Hello, John Doe!' => 'John Doe' * 'Hello, Chuck Norris!' => 'Chuck Norris' */ -function extractNameFromTemplate(/* value */) { - throw new Error('Not implemented'); +function extractNameFromTemplate(value) { + return value.split(',')[1].slice(0, -1).trim(); } @@ -80,9 +80,7 @@ function extractNameFromTemplate(/* value */) { * 'John Doe' => 'J' * 'cat' => 'c' */ -function getFirstChar(/* value */) { - throw new Error('Not implemented'); -} +const getFirstChar = (value) => value.slice(0, 1); /** * Removes a leading and trailing whitespace characters from string. @@ -95,8 +93,8 @@ function getFirstChar(/* value */) { * 'cat' => 'cat' * '\tHello, World! ' => 'Hello, World!' */ -function removeLeadingAndTrailingWhitespaces(/* value */) { - throw new Error('Not implemented'); +function removeLeadingAndTrailingWhitespaces(value) { + return value.trim(0, -1); } /** @@ -110,10 +108,11 @@ function removeLeadingAndTrailingWhitespaces(/* value */) { * 'A', 5 => 'AAAAA' * 'cat', 3 => 'catcatcat' */ -function repeatString(/* value, count */) { - throw new Error('Not implemented'); +function repeatString(value, count) { + return value.repeat(count); } + /** * Remove the first occurrence of string inside another string * @@ -126,8 +125,8 @@ function repeatString(/* value, count */) { * 'I like legends', 'end' => 'I like legs', * 'ABABAB','BA' => 'ABAB' */ -function removeFirstOccurrences(/* str, value */) { - throw new Error('Not implemented'); +function removeFirstOccurrences(str, value) { + return str.replace(value, ''); } /** @@ -141,8 +140,8 @@ function removeFirstOccurrences(/* str, value */) { * '' => 'span' * '' => 'a' */ -function unbracketTag(/* str */) { - throw new Error('Not implemented'); +function unbracketTag(str) { + return str.slice(1, -1); } @@ -156,8 +155,8 @@ function unbracketTag(/* str */) { * 'Thunderstruck' => 'THUNDERSTRUCK' * 'abcdefghijklmnopqrstuvwxyz' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' */ -function convertToUpperCase(/* str */) { - throw new Error('Not implemented'); +function convertToUpperCase(str) { + return str.toUpperCase(); } /** @@ -175,8 +174,8 @@ function convertToUpperCase(/* str */) { * ], * 'info@gmail.com' => ['info@gmail.com'] */ -function extractEmails(/* str */) { - throw new Error('Not implemented'); +function extractEmails(str) { + return str.split(';'); } /** @@ -202,11 +201,13 @@ function extractEmails(/* str */) { * '└──────────┘\n' * */ -function getRectangleString(/* width, height */) { - throw new Error('Not implemented'); +function getRectangleString(width, height) { + const first = `┌${'─'.repeat(width - 2)}┐\n`; + const middle = `│${' '.repeat(width - 2)}│\n`.repeat(height - 2); + const last = `└${'─'.repeat(width - 2)}┘\n`; + return first + middle + last; } - /** * Encode specified string with ROT13 cipher * See details: https://en.wikipedia.org/wiki/ROT13 @@ -223,10 +224,15 @@ function getRectangleString(/* width, height */) { * => 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm' * */ -function encodeToRot13(/* str */) { - throw new Error('Not implemented'); +function encodeToRot13(str) { + const GAP = 13; + const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM'; + const lower = 'abcdefghijklmnopqrstuvwxyzabcdefghijklm'; + const charEncoded = (char) => GAP + char.charCodeAt() - (char.charCodeAt() < 97 ? 65 : 97); + return str.replace(/[a-zA-Z]/g, (s) => (s.charCodeAt() < 97 ? upper[charEncoded(s)] : lower[charEncoded(s)])); } + /** * Returns true if the value is string; otherwise false. * @param {string} value @@ -240,8 +246,8 @@ function encodeToRot13(/* str */) { * isString('test') => true * isString(new String('test')) => true */ -function isString(/* value */) { - throw new Error('Not implemented'); +function isString(value) { + return typeof value === 'string' || value instanceof String; } @@ -269,8 +275,14 @@ function isString(/* value */) { * 'Q♠' => 50 * 'K♠' => 51 */ -function getCardId(/* value */) { - throw new Error('Not implemented'); +function getCardId(value) { + const deck = [ + 'A♣', '2♣', '3♣', '4♣', '5♣', '6♣', '7♣', '8♣', '9♣', '10♣', 'J♣', 'Q♣', 'K♣', + 'A♦', '2♦', '3♦', '4♦', '5♦', '6♦', '7♦', '8♦', '9♦', '10♦', 'J♦', 'Q♦', 'K♦', + 'A♥', '2♥', '3♥', '4♥', '5♥', '6♥', '7♥', '8♥', '9♥', '10♥', 'J♥', 'Q♥', 'K♥', + 'A♠', '2♠', '3♠', '4♠', '5♠', '6♠', '7♠', '8♠', '9♠', '10♠', 'J♠', 'Q♠', 'K♠', + ]; + return deck.indexOf(value); } diff --git a/src/02-numbers-tasks.js b/src/02-numbers-tasks.js index 2dd7964007..5ecf4cd19c 100644 --- a/src/02-numbers-tasks.js +++ b/src/02-numbers-tasks.js @@ -19,8 +19,8 @@ * 5, 10 => 50 * 5, 5 => 25 */ -function getRectangleArea(/* width, height */) { - throw new Error('Not implemented'); +function getRectangleArea(width, height) { + return width * height; } @@ -35,8 +35,8 @@ function getRectangleArea(/* width, height */) { * 3.14 => 19.729201864543903 * 0 => 0 */ -function getCircleCircumference(/* radius */) { - throw new Error('Not implemented'); +function getCircleCircumference(radius) { + return radius * 2 * Math.PI; } /** @@ -51,8 +51,11 @@ function getCircleCircumference(/* radius */) { * 10, 0 => 5 * -3, 3 => 0 */ -function getAverage(/* value1, value2 */) { - throw new Error('Not implemented'); +function getAverage(value1, value2) { + if (value1 === value2) return value1; + const vMax = Math.max(value1, value2); + const vMin = Math.min(value1, value2); + return vMin > 0 ? (vMax - vMin) / 2 : (vMax + vMin) / 2; } /** @@ -70,8 +73,10 @@ function getAverage(/* value1, value2 */) { * (0,0) (1,0) => 1 * (-5,0) (10,-10) => 18.027756377319946 */ -function getDistanceBetweenPoints(/* x1, y1, x2, y2 */) { - throw new Error('Not implemented'); +function getDistanceBetweenPoints(x1, y1, x2, y2) { + const a = x1 - x2; + const b = y1 - y2; + return Math.sqrt(a * a + b * b); } /** @@ -86,8 +91,8 @@ function getDistanceBetweenPoints(/* x1, y1, x2, y2 */) { * x + 8 = 0 => -8 * 5*x = 0 => 0 */ -function getLinearEquationRoot(/* a, b */) { - throw new Error('Not implemented'); +function getLinearEquationRoot(a, b) { + return -b / a; } @@ -109,8 +114,9 @@ function getLinearEquationRoot(/* a, b */) { * (0,1) (0,1) => 0 * (0,1) (1,2) => 0 */ -function getAngleBetweenVectors(/* x1, y1, x2, y2 */) { - throw new Error('Not implemented'); +function getAngleBetweenVectors(x1, y1, x2, y2) { + return Math.acos((x1 * x2 + y1 * y2) + / (Math.sqrt(x1 ** 2 + y1 ** 2) * Math.sqrt(x2 ** 2 + y2 ** 2))); } /** @@ -125,8 +131,8 @@ function getAngleBetweenVectors(/* x1, y1, x2, y2 */) { * 5 => 5 * 0 => 0 */ -function getLastDigit(/* value */) { - throw new Error('Not implemented'); +function getLastDigit(value) { + return Math.floor(value % 10); } @@ -141,8 +147,8 @@ function getLastDigit(/* value */) { * '37' => 37 * '-525.5' => -525.5 */ -function parseNumberFromString(/* value */) { - throw new Error('Not implemented'); +function parseNumberFromString(value) { + return +value; } /** @@ -158,8 +164,8 @@ function parseNumberFromString(/* value */) { * 3,3,3 => 5.196152422706632 * 1,2,3 => 3.741657386773941 */ -function getParallelepipedDiagonal(/* a, b, c */) { - throw new Error('Not implemented'); +function getParallelepipedDiagonal(a, b, c) { + return Math.sqrt(a ** 2 + b ** 2 + c ** 2); } @@ -180,8 +186,8 @@ function getParallelepipedDiagonal(/* a, b, c */) { * 1678, 2 => 1700 * 1678, 3 => 2000 */ -function roundToPowerOfTen(/* num, pow */) { - throw new Error('Not implemented'); +function roundToPowerOfTen(num, pow) { + return Math.round(num / 10 ** pow) * 10 ** pow; } /** @@ -201,8 +207,12 @@ function roundToPowerOfTen(/* num, pow */) { * 16 => false * 17 => true */ -function isPrime(/* n */) { - throw new Error('Not implemented'); +function isPrime(n) { + if (n <= 1) return false; + for (let i = 2; i <= Math.sqrt(n); i += 1) { + if (n % i === 0) return false; + } + return true; } /** @@ -220,8 +230,8 @@ function isPrime(/* n */) { * toNumber(42, 0) => 42 * toNumber(new Number(42), 0) => 42 */ -function toNumber(/* value, def */) { - throw new Error('Not implemented'); +function toNumber(value, def) { + return (typeof +value === 'number' && !Number.isNaN(+value)) ? +value : def; } module.exports = { diff --git a/src/03-arrays-tasks.js b/src/03-arrays-tasks.js index d9398fceb7..bbe6fb1dff 100644 --- a/src/03-arrays-tasks.js +++ b/src/03-arrays-tasks.js @@ -20,8 +20,8 @@ * ['Array', 'Number', 'string'], 'Date' => -1 * [0, 1, 2, 3, 4, 5], 5 => 5 */ -function findElement(/* arr, value */) { - throw new Error('Not implemented'); +function findElement(arr, value) { + return arr.findIndex((v) => v === value); } /** @@ -35,8 +35,8 @@ function findElement(/* arr, value */) { * 2 => [ 1, 3 ] * 5 => [ 1, 3, 5, 7, 9 ] */ -function generateOdds(/* len */) { - throw new Error('Not implemented'); +function generateOdds(len) { + return [...new Array(len)].map((_, i) => 2 * i + 1); } @@ -52,8 +52,8 @@ function generateOdds(/* len */) { * [0, 1, 2, 3, 4, 5] => [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5] * [] => [] */ -function doubleArray(/* arr */) { - throw new Error('Not implemented'); +function doubleArray(arr) { + return [...arr, ...arr]; } @@ -68,8 +68,9 @@ function doubleArray(/* arr */) { * [-1, 2, -5, -4, 0] => [ 2 ] * [] => [] */ -function getArrayOfPositives(/* arr */) { - throw new Error('Not implemented'); +function getArrayOfPositives(arr) { + const posArr = arr.filter((num) => num > 0); + return posArr; } /** @@ -83,8 +84,8 @@ function getArrayOfPositives(/* arr */) { * [ 1, 2, 3, 4, 5 ] => [] * [ 'cat, 'dog', 'raccoon' ] => [ 'cat', 'dog', 'raccoon' ] */ -function getArrayOfStrings(/* arr */) { - throw new Error('Not implemented'); +function getArrayOfStrings(arr) { + return arr.filter((num) => typeof num === 'string'); } /** @@ -100,8 +101,8 @@ function getArrayOfStrings(/* arr */) { * [ 1, 2, 3, 4, 5, 'false' ] => [ 1, 2, 3, 4, 5, 'false' ] * [ false, 0, NaN, '', undefined ] => [ ] */ -function removeFalsyValues(/* arr */) { - throw new Error('Not implemented'); +function removeFalsyValues(arr) { + return arr.filter((num) => !!num); } /** @@ -115,8 +116,8 @@ function removeFalsyValues(/* arr */) { * => [ 'PERMANENT-INTERNSHIP', 'GLUTINOUS-SHRIEK', 'MULTIPLICATIVE-ELEVATION' ], * [ 'a', 'b', 'c', 'd', 'e', 'f', 'g' ] => [ 'A', 'B', 'C', 'D', 'E', 'F', 'G' ] */ -function getUpperCaseStrings(/* arr */) { - throw new Error('Not implemented'); +function getUpperCaseStrings(arr) { + return arr.map((num) => num.toUpperCase()); } @@ -130,8 +131,8 @@ function getUpperCaseStrings(/* arr */) { * [ '', 'a', 'bc', 'def', 'ghij' ] => [ 0, 1, 2, 3, 4 ] * [ 'angular', 'react', 'ember' ] => [ 7, 5, 5 ] */ -function getStringsLength(/* arr */) { - throw new Error('Not implemented'); +function getStringsLength(arr) { + return arr.map((num) => num.length); } /** @@ -145,10 +146,12 @@ function getStringsLength(/* arr */) { * [ 1, 3, 4, 5 ], 2, 1 => [ 1, 2, 3, 4, 5 ] * [ 1, 'b', 'c'], 'x', 0 => [ 'x', 1, 'b', 'c' ] */ -function insertItem(/* arr, item, index */) { - throw new Error('Not implemented'); +function insertItem(arr, item, index) { + arr.splice(index, 0, item); + return arr; } + /** * Returns the n first items of the specified array * @@ -159,8 +162,8 @@ function insertItem(/* arr, item, index */) { * [ 1, 3, 4, 5 ], 2 => [ 1, 3 ] * [ 'a', 'b', 'c', 'd'], 3 => [ 'a', 'b', 'c' ] */ -function getHead(/* arr, n */) { - throw new Error('Not implemented'); +function getHead(arr, n) { + return arr.slice(0, n); } @@ -174,8 +177,8 @@ function getHead(/* arr, n */) { * [ 1, 3, 4, 5 ], 2 => [ 4, 5 ] * [ 'a', 'b', 'c', 'd'], 3 => [ 'b', 'c', 'd' ] */ -function getTail(/* arr, n */) { - throw new Error('Not implemented'); +function getTail(arr, n) { + return arr.slice(-n); } @@ -199,8 +202,8 @@ function getTail(/* arr, n */) { * +'20,21,22,23,24\n' * +'30,31,32,33,34' */ -function toCsvText(/* arr */) { - throw new Error('Not implemented'); +function toCsvText(arr) { + return arr.map((v) => v.join(',')).join('\n'); } /** @@ -214,8 +217,8 @@ function toCsvText(/* arr */) { * [ 0, 1, 2, 3, 4, 5 ] => [ 0, 1, 4, 9, 16, 25 ] * [ 10, 100, -1 ] => [ 100, 10000, 1 ] */ -function toArrayOfSquares(/* arr */) { - throw new Error('Not implemented'); +function toArrayOfSquares(arr) { + return arr.map((x) => x ** 2); } @@ -233,8 +236,8 @@ function toArrayOfSquares(/* arr */) { * [ 0, 0, 0, 0, 0] => [ 0, 0, 0, 0, 0] * [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] => [ 1, 3, 6, 10, 15, 21, 28, 36, 45, 55 ] */ -function getMovingSum(/* arr */) { - throw new Error('Not implemented'); +function getMovingSum(arr) { + return arr.map((elem, i) => elem + arr.slice(0, i).reduce((a, b) => a + b, 0)); } /** @@ -248,8 +251,8 @@ function getMovingSum(/* arr */) { * [ 'a', 'b', 'c' , null ] => [ "b", null ] * [ "a" ] => [] */ -function getSecondItems(/* arr */) { - throw new Error('Not implemented'); +function getSecondItems(arr) { + return arr.filter((_, i) => i % 2 === 1); } @@ -267,8 +270,8 @@ function getSecondItems(/* arr */) { * [ 'a', 'b', 'c', null ] => [ 'a', 'b','b', 'c','c','c', null,null,null,null ] * [ 1,2,3,4,5 ] => [ 1, 2,2, 3,3,3, 4,4,4,4, 5,5,5,5,5 ] */ -function propagateItemsByPositionIndex(/* arr */) { - throw new Error('Not implemented'); +function propagateItemsByPositionIndex(arr) { + return arr.map((elem, i) => [Array(i + 1).fill(elem)]).flat(2); } @@ -285,8 +288,8 @@ function propagateItemsByPositionIndex(/* arr */) { * [ 1,2,3,4,5,6,7,8,9,10 ] => [ 10, 9, 8 ] * [ 10, 10, 10, 10 ] => [ 10, 10, 10 ] */ -function get3TopItems(/* arr */) { - throw new Error('Not implemented'); +function get3TopItems(arr) { + return arr.sort((a, b) => b - a).slice(0, 3); } @@ -303,8 +306,8 @@ function get3TopItems(/* arr */) { * [ null, 1, 'elephant' ] => 1 * [ 1, '2' ] => 1 */ -function getPositivesCount(/* arr */) { - throw new Error('Not implemented'); +function getPositivesCount(arr) { + return arr.filter((v) => typeof v === 'number' && v > 0).length; } /** @@ -320,8 +323,20 @@ function getPositivesCount(/* arr */) { * [ 'nine','eight','nine','eight'] => [ 'eight','eight','nine','nine'] * [ 'one','one','one','zero' ] => [ 'zero','one','one','one' ] */ -function sortDigitNamesByNumericOrder(/* arr */) { - throw new Error('Not implemented'); +function sortDigitNamesByNumericOrder(arr) { + const nums = [ + 'zero', + 'one', + 'two', + 'three', + 'four', + 'five', + 'six', + 'seven', + 'eight', + 'nine', + ]; + return arr.sort((a, b) => nums.indexOf(a) - nums.indexOf(b)); } /** @@ -336,8 +351,8 @@ function sortDigitNamesByNumericOrder(/* arr */) { * [ -1, 1, -1, 1 ] => 0 * [ 1, 10, 100, 1000 ] => 1111 */ -function getItemsSum(/* arr */) { - throw new Error('Not implemented'); +function getItemsSum(arr) { + return arr.reduce((acc, cur) => acc + cur, 0); } /** @@ -352,8 +367,8 @@ function getItemsSum(/* arr */) { * [ -1, 'false', null, 0 ] => 2 * [ null, undefined, NaN, false, 0, '' ] => 6 */ -function getFalsyValuesCount(/* arr */) { - throw new Error('Not implemented'); +function getFalsyValuesCount(arr) { + return arr.filter((elem) => !elem).length; } /** @@ -370,8 +385,8 @@ function getFalsyValuesCount(/* arr */) { * [ null, undefined, null ], null => 2 * [ true, 0, 1, 'true' ], true => 1 */ -function findAllOccurrences(/* arr, item */) { - throw new Error('Not implemented'); +function findAllOccurrences(arr, item) { + return arr.filter((i) => i === item).length; } /** @@ -385,8 +400,8 @@ function findAllOccurrences(/* arr, item */) { * [1, 2, 3, 4, 5] => '1,2,3,4,5' * ['rock', 'paper', 'scissors'] => 'rock,paper,scissors' */ -function toStringList(/* arr */) { - throw new Error('Not implemented'); +function toStringList(arr) { + return arr.join(','); } @@ -416,8 +431,14 @@ function toStringList(/* arr */) { * { country: 'Russia', city: 'Saint Petersburg' } * ] */ -function sortCitiesArray(/* arr */) { - throw new Error('Not implemented'); +function sortCitiesArray(arr) { + return arr.sort((a, b) => { + if (a.country > b.country) return 1; + if (a.country < b.country) return -1; + if (a.city > b.city) return 1; + if (a.city < b.city) return -1; + return 0; + }); } /** @@ -438,8 +459,8 @@ function sortCitiesArray(/* arr */) { * [0,0,0,1,0], * [0,0,0,0,1]] */ -function getIdentityMatrix(/* n */) { - throw new Error('Not implemented'); +function getIdentityMatrix(n) { + return [...Array(n)].map((_, i) => [...Array(n)].map((__, j) => (i === j ? 1 : 0))); } /** @@ -455,8 +476,8 @@ function getIdentityMatrix(/* n */) { * 0, 100 => [ 0, 1, 2, ..., 100 ] * 3, 3 => [ 3 ] */ -function getIntervalArray(/* start, end */) { - throw new Error('Not implemented'); +function getIntervalArray(start, end) { + return Array(end - start + 1).fill(0).map((_, i) => start + i); } /** @@ -470,8 +491,8 @@ function getIntervalArray(/* start, end */) { * [ 'a', 'a', 'a', 'a' ] => [ 'a' ] * [ 1, 1, 2, 2, 3, 3, 4, 4] => [ 1, 2, 3, 4] */ -function distinct(/* arr */) { - throw new Error('Not implemented'); +function distinct(arr) { + return [...new Set(arr)]; } /** @@ -504,8 +525,16 @@ function distinct(/* arr */) { * "Poland" => ["Lodz"] * } */ -function group(/* array, keySelector, valueSelector */) { - throw new Error('Not implemented'); +function group(array, keySelector, valueSelector) { + const result = {}; + array.map((item) => { + const key = keySelector(item); + const value = valueSelector(item); + if (!result[key]) result[key] = []; + result[key].push(value); + return item; + }); + return new Map(Object.entries(result)); } @@ -522,8 +551,8 @@ function group(/* array, keySelector, valueSelector */) { * [[1, 2], [3, 4], [5, 6]], (x) => x => [ 1, 2, 3, 4, 5, 6 ] * ['one','two','three'], (x) => x.split('') => ['o','n','e','t','w','o','t','h','r','e','e'] */ -function selectMany(/* arr, childrenSelector */) { - throw new Error('Not implemented'); +function selectMany(arr, childrenSelector) { + return arr.map((v) => childrenSelector(v)).flat(); } @@ -539,8 +568,8 @@ function selectMany(/* arr, childrenSelector */) { * ['one','two','three'], [2] => 'three' (arr[2]) * [[[ 1, 2, 3]]], [ 0, 0, 1 ] => 2 (arr[0][0][1]) */ -function getElementByIndexes(/* arr, indexes */) { - throw new Error('Not implemented'); +function getElementByIndexes(arr, indexes) { + return indexes.reduce((res, current) => res[current], arr); } @@ -562,8 +591,14 @@ function getElementByIndexes(/* arr, indexes */) { * [ 1, 2, 3, 4, 5, 6, 7, 8 ] => [ 5, 6, 7, 8, 1, 2, 3, 4 ] * */ -function swapHeadAndTail(/* arr */) { - throw new Error('Not implemented'); +function swapHeadAndTail(arr) { + const result = []; + const leftIndex = Math.floor(arr.length / 2); + const rightIndex = Math.ceil(arr.length / 2); + result.push(...arr.slice(rightIndex)); + if (arr.length % 2 !== 0) result.push(arr[leftIndex]); + result.push(...arr.slice(0, leftIndex)); + return result; } diff --git a/src/04-date-tasks.js b/src/04-date-tasks.js index 95ffe2d10d..29704859e7 100644 --- a/src/04-date-tasks.js +++ b/src/04-date-tasks.js @@ -19,8 +19,8 @@ * 'Tue, 26 Jan 2016 13:48:02 GMT' => Date() * 'Sun, 17 May 1998 03:00:00 GMT+01' => Date() */ -function parseDataFromRfc2822(/* value */) { - throw new Error('Not implemented'); +function parseDataFromRfc2822(value) { + return Date.parse(value); } /** @@ -34,8 +34,8 @@ function parseDataFromRfc2822(/* value */) { * '2016-01-19T16:07:37+00:00' => Date() * '2016-01-19T08:07:37Z' => Date() */ -function parseDataFromIso8601(/* value */) { - throw new Error('Not implemented'); +function parseDataFromIso8601(value) { + return Date.parse(value); } @@ -53,8 +53,12 @@ function parseDataFromIso8601(/* value */) { * Date(2012,1,1) => true * Date(2015,1,1) => false */ -function isLeapYear(/* date */) { - throw new Error('Not implemented'); +function isLeapYear(date) { + const year = date.getFullYear(); + if (year % 4 !== 0) return false; + if (year % 100 !== 0) return true; + if (year % 400 !== 0) return false; + return true; } @@ -73,8 +77,13 @@ function isLeapYear(/* date */) { * Date(2000,1,1,10,0,0), Date(2000,1,1,10,0,0,250) => "00:00:00.250" * Date(2000,1,1,10,0,0), Date(2000,1,1,15,20,10,453) => "05:20:10.453" */ -function timeSpanToString(/* startDate, endDate */) { - throw new Error('Not implemented'); +function timeSpanToString(startDate, endDate) { + const diff = endDate - startDate; + const hours = Math.floor(diff / 1000 / 60 / 60).toString().padStart(2, '0'); + const minutes = Math.floor((diff / 1000 / 60) % 60).toString().padStart(2, '0'); + const seconds = Math.floor((diff / 1000) % 60).toString().padStart(2, '0'); + const milliSecondes = (diff % 1000).toString().padStart(3, '0'); + return `${hours}:${minutes}:${seconds}.${milliSecondes}`; } @@ -94,8 +103,20 @@ function timeSpanToString(/* startDate, endDate */) { * Date.UTC(2016,3,5,18, 0) => Math.PI * Date.UTC(2016,3,5,21, 0) => Math.PI/2 */ -function angleBetweenClockHands(/* date */) { - throw new Error('Not implemented'); +function angleBetweenClockHands(dateUtc) { + const date = new Date(dateUtc); + const h = date.getUTCHours(); + const m = date.getUTCMinutes(); + + const mAngle = m * 6; + const hAngle = (30 * (h + m / 60)) % 360; + + const maxAngle = Math.max(mAngle, hAngle); + const minAngle = Math.min(mAngle, hAngle); + + const angle = Math.min(maxAngle - minAngle, 360 - maxAngle + minAngle); + + return Math.PI * (angle / 180); } diff --git a/src/05-objects-tasks.js b/src/05-objects-tasks.js index f26fc4f7a2..959803f9ef 100644 --- a/src/05-objects-tasks.js +++ b/src/05-objects-tasks.js @@ -20,8 +20,10 @@ * console.log(r.height); // => 20 * console.log(r.getArea()); // => 200 */ -function Rectangle(/* width, height */) { - throw new Error('Not implemented'); +function Rectangle(width, height) { + this.width = width; + this.height = height; + this.getArea = () => this.width * this.height; } @@ -35,8 +37,8 @@ function Rectangle(/* width, height */) { * [1,2,3] => '[1,2,3]' * { width: 10, height : 20 } => '{"height":10,"width":20}' */ -function getJSON(/* obj */) { - throw new Error('Not implemented'); +function getJSON(obj) { + return JSON.stringify(obj); } @@ -51,8 +53,8 @@ function getJSON(/* obj */) { * const r = fromJSON(Circle.prototype, '{"radius":10}'); * */ -function fromJSON(/* proto, json */) { - throw new Error('Not implemented'); +function fromJSON(proto, json) { + return new proto.constructor(...Object.values(JSON.parse(json))); } @@ -109,35 +111,116 @@ function fromJSON(/* proto, json */) { * * For more examples see unit tests. */ +class CssSelectors { + constructor() { + this.selector = ''; + this.selectorChunksToCheck = { + element: 0, + id: 0, + pseudoElement: 0, + }; + this.selectorChunksOrder = 0; + this.errors = { + onlyOneTime: 'Element, id and pseudo-element should not occur more then one time inside the selector', + selectorsOrder: 'Selector parts should be arranged in the following order: element, id, class, attribute, pseudo-class, pseudo-element', + }; + } + + checkSelectorOnlyOneTimeOccur(selector) { + const { onlyOneTime } = this.errors; + if (this.selectorChunksToCheck[selector]) throw new Error(onlyOneTime); + } + + checkSelectorsOrder(currentSelectorDefaultOrder) { + const { selectorChunksOrder } = this; + const { selectorsOrder } = this.errors; + if (selectorChunksOrder > currentSelectorDefaultOrder) throw new Error(selectorsOrder); + } + + element(value) { + const currentSelectorDefaultOrder = 1; + + this.checkSelectorOnlyOneTimeOccur('element'); + this.checkSelectorsOrder(currentSelectorDefaultOrder); + + this.selector += value; + this.selectorChunksToCheck.element = 1; + this.selectorChunksOrder = currentSelectorDefaultOrder; + return this; + } + + id(value) { + const currentSelectorDefaultOrder = 2; + + this.checkSelectorOnlyOneTimeOccur('id'); + this.checkSelectorsOrder(currentSelectorDefaultOrder); + + this.selector += `#${value}`; + this.selectorChunksToCheck.id = 1; + this.selectorChunksOrder = currentSelectorDefaultOrder; + return this; + } + + class(value) { + const currentSelectorDefaultOrder = 3; + + this.checkSelectorsOrder(currentSelectorDefaultOrder); + + this.selector += `.${value}`; + this.selectorChunksOrder = currentSelectorDefaultOrder; + return this; + } + + attr(value) { + const currentSelectorDefaultOrder = 4; + + this.checkSelectorsOrder(currentSelectorDefaultOrder); + + this.selector += `[${value}]`; + this.selectorChunksOrder = currentSelectorDefaultOrder; + return this; + } + + pseudoClass(value) { + const currentSelectorDefaultOrder = 5; + + this.checkSelectorsOrder(currentSelectorDefaultOrder); + + this.selector += `:${value}`; + this.selectorChunksOrder = currentSelectorDefaultOrder; + return this; + } + + pseudoElement(value) { + const currentSelectorDefaultOrder = 6; + + this.checkSelectorOnlyOneTimeOccur('pseudoElement'); + this.checkSelectorsOrder(currentSelectorDefaultOrder); + + this.selector += `::${value}`; + this.selectorChunksToCheck.pseudoElement = 1; + this.selectorChunksOrder = currentSelectorDefaultOrder; + return this; + } + + combine(s1, combinator, s2) { + this.selector = `${s1.selector} ${combinator} ${s2.selector}`; + return this; + } + + stringify() { + return this.selector; + } +} const cssSelectorBuilder = { - element(/* value */) { - throw new Error('Not implemented'); - }, - - id(/* value */) { - throw new Error('Not implemented'); - }, - - class(/* value */) { - throw new Error('Not implemented'); - }, - - attr(/* value */) { - throw new Error('Not implemented'); - }, - - pseudoClass(/* value */) { - throw new Error('Not implemented'); - }, - - pseudoElement(/* value */) { - throw new Error('Not implemented'); - }, - - combine(/* selector1, combinator, selector2 */) { - throw new Error('Not implemented'); - }, + element: (value) => new CssSelectors().element(value), + id: (value) => new CssSelectors().id(value), + class: (value) => new CssSelectors().class(value), + attr: (value) => new CssSelectors().attr(value), + pseudoClass: (value) => new CssSelectors().pseudoClass(value), + pseudoElement: (value) => new CssSelectors().pseudoElement(value), + combine: (s1, combinator, s2) => new CssSelectors().combine(s1, combinator, s2), }; diff --git a/src/06-promises-tasks.js b/src/06-promises-tasks.js index cb6dcd8f52..fefffdd005 100644 --- a/src/06-promises-tasks.js +++ b/src/06-promises-tasks.js @@ -28,8 +28,11 @@ * .catch((error) => console.log(error.message)) // 'Error: Wrong parameter is passed! * // Ask her again.'; */ -function willYouMarryMe(/* isPositiveAnswer */) { - throw new Error('Not implemented'); +async function willYouMarryMe(isPositiveAnswer) { + if (isPositiveAnswer === undefined) throw new Error('Wrong parameter is passed! Ask her again.'); + return isPositiveAnswer + ? 'Hooray!!! She said "Yes"!' + : 'Oh no, she said "No".'; } @@ -48,8 +51,8 @@ function willYouMarryMe(/* isPositiveAnswer */) { * }) * */ -function processAllPromises(/* array */) { - throw new Error('Not implemented'); +function processAllPromises(array) { + return Promise.all(array); } /** @@ -71,8 +74,8 @@ function processAllPromises(/* array */) { * }) * */ -function getFastestPromise(/* array */) { - throw new Error('Not implemented'); +function getFastestPromise(array) { + return Promise.race(array); } /** @@ -92,8 +95,14 @@ function getFastestPromise(/* array */) { * }); * */ -function chainPromises(/* array, action */) { - throw new Error('Not implemented'); +function chainPromises(array, action) { + return array.reduce(async (firstPromise, secondPromise) => { + try { + return action(await firstPromise, await secondPromise); + } catch (error) { + return error.message; + } + }); } module.exports = { diff --git a/src/07-conditions-n-loops-tasks.js b/src/07-conditions-n-loops-tasks.js index 5807f20fef..60f5ed536e 100644 --- a/src/07-conditions-n-loops-tasks.js +++ b/src/07-conditions-n-loops-tasks.js @@ -27,8 +27,11 @@ * 21 => 'Fizz' * */ -function getFizzBuzz(/* num */) { - throw new Error('Not implemented'); +function getFizzBuzz(num) { + if (num % 3 === 0 && num % 5 === 0) return 'FizzBuzz'; + if (num % 3 === 0) return 'Fizz'; + if (num % 5 === 0) return 'Buzz'; + return num; } @@ -43,8 +46,8 @@ function getFizzBuzz(/* num */) { * 5 => 120 * 10 => 3628800 */ -function getFactorial(/* n */) { - throw new Error('Not implemented'); +function getFactorial(n) { + return n === 1 ? n : n * getFactorial(n - 1); } @@ -60,8 +63,8 @@ function getFactorial(/* n */) { * 5,10 => 45 ( = 5+6+7+8+9+10 ) * -1,1 => 0 ( = -1 + 0 + 1 ) */ -function getSumBetweenNumbers(/* n1, n2 */) { - throw new Error('Not implemented'); +function getSumBetweenNumbers(n1, n2) { + return n1 === n2 ? n1 : n1 + getSumBetweenNumbers(n1 + 1, n2); } @@ -80,8 +83,8 @@ function getSumBetweenNumbers(/* n1, n2 */) { * 10,1,1 => false * 10,10,10 => true */ -function isTriangle(/* a, b, c */) { - throw new Error('Not implemented'); +function isTriangle(a, b, c) { + return (a + b + c) / 2 > Math.max(a, b, c); } @@ -117,8 +120,18 @@ function isTriangle(/* a, b, c */) { * { top:20, left:20, width: 20, height: 20 } => false * */ -function doRectanglesOverlap(/* rect1, rect2 */) { - throw new Error('Not implemented'); +function doRectanglesOverlap(rect1, rect2) { + const { + left: r1x, top: r1y, width: r1w, height: r1h, + } = rect1; + const { + left: r2x, top: r2y, width: r2w, height: r2h, + } = rect2; + + return (r1x + r1w - r2x > 0) + && (r2x + r2w - r1x > 0) + && (r1y + r1h - r2y > 0) + && (r2y + r2h - r1y > 0); } @@ -148,8 +161,11 @@ function doRectanglesOverlap(/* rect1, rect2 */) { * { center: { x:0, y:0 }, radius:10 }, { x:10, y:10 } => false * */ -function isInsideCircle(/* circle, point */) { - throw new Error('Not implemented'); +function isInsideCircle(circle, point) { + const { center, radius } = circle; + const { x: xCenter, y: yCenter } = center; + const { x: xPoint, y: yPoint } = point; + return radius ** 2 > (xPoint - xCenter) ** 2 + (yPoint - yCenter) ** 2; } @@ -164,8 +180,14 @@ function isInsideCircle(/* circle, point */) { * 'abracadabra' => 'c' * 'entente' => null */ -function findFirstSingleChar(/* str */) { - throw new Error('Not implemented'); +function findFirstSingleChar(str) { + let char = null; + let i = 0; + while (!char && i < str.length) { + if (str.indexOf(str[i]) === str.lastIndexOf(str[i])) char = str[i]; + i += 1; + } + return char; } @@ -191,8 +213,8 @@ function findFirstSingleChar(/* str */) { * 5, 3, true, true => '[3, 5]' * */ -function getIntervalString(/* a, b, isStartIncluded, isEndIncluded */) { - throw new Error('Not implemented'); +function getIntervalString(a, b, isStart, isEnd) { + return `${isStart ? '[' : '('}${Math.min(a, b)}, ${Math.max(a, b)}${isEnd ? ']' : ')'}`; } @@ -208,8 +230,8 @@ function getIntervalString(/* a, b, isStartIncluded, isEndIncluded */) { * 'rotator' => 'rotator' * 'noon' => 'noon' */ -function reverseString(/* str */) { - throw new Error('Not implemented'); +function reverseString(str) { + return str.split('').reverse().join(''); } @@ -225,8 +247,8 @@ function reverseString(/* str */) { * 87354 => 45378 * 34143 => 34143 */ -function reverseInteger(/* num */) { - throw new Error('Not implemented'); +function reverseInteger(num) { + return +num.toString().split('').reverse().join(''); } @@ -250,8 +272,19 @@ function reverseInteger(/* num */) { * 5436468789016589 => false * 4916123456789012 => false */ -function isCreditCardNumber(/* ccn */) { - throw new Error('Not implemented'); +function isCreditCardNumber(ccn) { + const [controlDigit] = ccn.toString().split('').slice(-1); + const sumOfDigits = ccn + .toString() + .split('') + .slice(0, -1) + .reverse() + .reduce((acc, digit, index) => { + const num = +digit * (index % 2 ? 1 : 2); + return acc + (num > 9 ? num - 9 : num); + }, 0); + const controlDigitCalculated = (10 - (sumOfDigits % 10)) % 10; + return +controlDigit === controlDigitCalculated; } /** @@ -268,8 +301,9 @@ function isCreditCardNumber(/* ccn */) { * 10000 ( 1+0+0+0+0 = 1 ) => 1 * 165536 (1+6+5+5+3+6 = 26, 2+6 = 8) => 8 */ -function getDigitalRoot(/* num */) { - throw new Error('Not implemented'); +function getDigitalRoot(num) { + const sum = num.toString().split('').reduce((a, c) => a + +c, 0); + return sum > 9 ? getDigitalRoot(sum) : sum; } @@ -294,8 +328,17 @@ function getDigitalRoot(/* num */) { * '{)' = false * '{[(<{[]}>)]}' = true */ -function isBracketsBalanced(/* str */) { - throw new Error('Not implemented'); +function isBracketsBalanced(str) { + let result = str; + const bracketPairs = ['[]', '()', '{}', '<>']; + const re = new RegExp(/\[\]|\(\)|{}|<>/, 'g'); + const isBracketsInResult = (bracketPair) => result.includes(bracketPair); + let isSearch = true; + while (isSearch) { + result = result.replace(re, ''); + isSearch = bracketPairs.some(isBracketsInResult); + } + return !result.length; } @@ -319,8 +362,8 @@ function isBracketsBalanced(/* str */) { * 365, 4 => '11231' * 365, 10 => '365' */ -function toNaryString(/* num, n */) { - throw new Error('Not implemented'); +function toNaryString(num, n) { + return num.toString(n); } @@ -336,8 +379,23 @@ function toNaryString(/* num, n */) { * ['/web/assets/style.css', '/.bin/mocha', '/read.me'] => '/' * ['/web/favicon.ico', '/web-scripts/dump', '/verbalizer/logs'] => '/' */ -function getCommonDirectoryPath(/* pathes */) { - throw new Error('Not implemented'); +function getCommonDirectoryPath(pathes) { + if (!pathes || !pathes.length) return ''; + if (pathes.some((path) => path.slice(0, 1) !== '/')) return ''; + + const pathesEdited = pathes + .map((path) => path.split('/').filter(Boolean)) + .sort((a, b) => b.length - a.length); + + const [maxLengthPath] = pathesEdited; + const commonPath = ['/']; + + for (let i = 0; i < maxLengthPath.length; i += 1) { + if (!pathesEdited.every((path) => path[i] === maxLengthPath[i])) break; + commonPath.push(`${maxLengthPath[i]}/`); + } + + return commonPath.join(''); } @@ -359,8 +417,20 @@ function getCommonDirectoryPath(/* pathes */) { * [ 6 ]] * */ -function getMatrixProduct(/* m1, m2 */) { - throw new Error('Not implemented'); +function getMatrixProduct(m1, m2) { + const resultMatrix = []; + for (let i = 0; i < m1.length; i += 1) { + const row = []; + for (let j = 0; j < m2[i].length; j += 1) { + let rowElement = 0; + for (let n = 0; n < m2.length; n += 1) { + rowElement += m1[i][n] * m2[n][j]; + } + row.push(rowElement); + } + resultMatrix.push(row); + } + return resultMatrix; } @@ -394,8 +464,34 @@ function getMatrixProduct(/* m1, m2 */) { * [ , , ]] * */ -function evaluateTicTacToePosition(/* position */) { - throw new Error('Not implemented'); +function evaluateTicTacToePosition(position) { + const symbolOne = 'X'; + const symbolTwo = '0'; + const boardSize = 3; + + const lines = []; + const diagonal1 = []; + const diagonal2 = []; + + for (let i = 0; i < boardSize; i += 1) { + const row = []; + const column = []; + for (let j = 0; j < boardSize; j += 1) { + row.push(position[i][j]); + column.push(position[j][i]); + if (i === j) diagonal1.push(position[i][j]); + if (i + j === boardSize - 1) diagonal2.push(position[i][j]); + } + lines.push(row.join('')); + lines.push(column.join('')); + } + + lines.push(diagonal1.join('')); + lines.push(diagonal2.join('')); + + if (lines.includes(symbolOne.repeat(boardSize))) return symbolOne; + if (lines.includes(symbolTwo.repeat(boardSize))) return symbolTwo; + return undefined; } diff --git a/src/08-functions-n-closures-tasks.js b/src/08-functions-n-closures-tasks.js index 299a639583..559cc543e5 100644 --- a/src/08-functions-n-closures-tasks.js +++ b/src/08-functions-n-closures-tasks.js @@ -23,8 +23,8 @@ * getComposition(Math.sin, Math.asin)(x) => Math.sin(Math.asin(x)) * */ -function getComposition(/* f, g */) { - throw new Error('Not implemented'); +function getComposition(f, g) { + return (x) => f(g(x)); } @@ -44,8 +44,8 @@ function getComposition(/* f, g */) { * power05(16) => 4 * */ -function getPowerFunction(/* exponent */) { - throw new Error('Not implemented'); +function getPowerFunction(e) { + return (x) => x ** e; } @@ -62,8 +62,13 @@ function getPowerFunction(/* exponent */) { * getPolynom(8) => y = 8 * getPolynom() => null */ -function getPolynom() { - throw new Error('Not implemented'); +function getPolynom(...nums) { + return (x) => { + const result = []; + const { length } = nums; + nums.forEach((num, index) => result.push(num * x ** (length - index - 1))); + return result.reduce((a, b) => a + b); + }; } @@ -81,8 +86,13 @@ function getPolynom() { * ... * memoizer() => the same random number (next run, returns the previous cached result) */ -function memoize(/* func */) { - throw new Error('Not implemented'); +function memoize(func) { + let x; + return (...args) => { + if (x) return x; + x = func(...args); + return x; + }; } @@ -101,8 +111,14 @@ function memoize(/* func */) { * }, 2); * retryer() => 2 */ -function retry(/* func, attempts */) { - throw new Error('Not implemented'); +function retry(func, attempts) { + return () => { + try { + return func(); + } catch (error) { + return retry(func, attempts)(); + } + }; } @@ -129,8 +145,14 @@ function retry(/* func, attempts */) { * cos(3.141592653589793) ends * */ -function logger(/* func, logFunc */) { - throw new Error('Not implemented'); +function logger(func, logFunc) { + return (...args) => { + const argsToString = args.map((arg) => JSON.stringify(arg)).join(','); + logFunc(`${func.name}(${argsToString}) starts`); + const result = func(...args); + logFunc(`${func.name}(${argsToString}) ends`); + return result; + }; } @@ -147,8 +169,8 @@ function logger(/* func, logFunc */) { * partialUsingArguments(fn, 'a','b','c')('d') => 'abcd' * partialUsingArguments(fn, 'a','b','c','d')() => 'abcd' */ -function partialUsingArguments(/* fn, ...args1 */) { - throw new Error('Not implemented'); +function partialUsingArguments(fn, ...args1) { + return (...args2) => fn(...args1, ...args2); } @@ -169,8 +191,12 @@ function partialUsingArguments(/* fn, ...args1 */) { * getId4() => 7 * getId10() => 11 */ -function getIdGeneratorFunction(/* startFrom */) { - throw new Error('Not implemented'); +function getIdGeneratorFunction(startFrom) { + let x = startFrom; + return () => { + x += 1; + return x - 1; + }; }