diff --git a/.gitignore b/.gitignore index 9fe5cb489..22010c5cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ currentSnippet\.js *.md.temp.js +.idea diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..df46a145a --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at chalarangelo@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40e6f2a17..15aab603c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,6 +29,7 @@ Here's what you can do to help: - Try to keep your snippets' code short and to the point. Use modern techniques and features. Make sure to test your code before submitting. - All snippets must be followed by one (more if necessary) test case after the code, on a new line, in the form of a comment, along with the expected output. The syntax for this is `myFunction('testInput') -> 'testOutput'`. Use multiline comments only if necessary. - Try to make your function name unique, so that it does not conflict with existing snippets. + - Snippet functions do not have to handle errors in input, unless it's necessary (e.g. a mathematical function that cannot be extended to negative numbers should handle negative input appropriately). - Snippets should be short (usually below 10 lines). If your snippet is longer than that, you can still submit it, and we can help you shorten it or figure out ways to improve it. - Snippets *should* solve real-world problems, no matter how simple. - Snippets *should* be abstract enough to be applied to different scenarios. @@ -54,7 +55,8 @@ Here's what you can do to help: - `i` for indexes. - `func` for function arguments. - `nums` for arrays of numbers. -- Use `_` if your function takes no arguments or if an argument inside some function (e.g. `Array.reduce()`) is not used anywhere in your code. +- Use `()` if your function takes no arguments. +- Use `_` if an argument inside some function (e.g. `Array.reduce()`) is not used anywhere in your code. - Specify default parameters for arguments, if necessary. It is preferred to put default parameters last unless you have pretty good reason not to. - If your snippet's function takes variadic arguments, use `..args` (although in certain cases, it might be needed to use a different name). - If your snippet function's body is a single statement, omit the `return` keyword and use an expression instead. diff --git a/README.md b/README.md index c15a1a0cb..c9dd3b8b4 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ ## Table of Contents ### Array -* [Array concatenation](#array-concatenation) * [Array difference](#array-difference) -* [Array includes](#array-includes) * [Array intersection](#array-intersection) +* [Array pull (mutates array)](#array-pull-mutates-array) * [Array remove](#array-remove) * [Array sample](#array-sample) +* [Array symmetric difference](#array-symmetric-difference) * [Array union](#array-union) * [Array without](#array-without) * [Array zip](#array-zip) @@ -25,7 +25,6 @@ * [Count occurrences of a value in array](#count-occurrences-of-a-value-in-array) * [Deep flatten array](#deep-flatten-array) * [Drop elements in array](#drop-elements-in-array) -* [Fill array](#fill-array) * [Filter out non unique values in an array](#filter-out-non-unique-values-in-an-array) * [Flatten array up to depth](#flatten-array-up-to-depth) * [Flatten array](#flatten-array) @@ -58,12 +57,15 @@ * [Scroll to top](#scroll-to-top) ### Date +* [Convert to english date](#convert-to-english-date) * [Get days difference between dates](#get-days-difference-between-dates) +* [JSON to date](#json-to-date) ### Function * [Chain asynchronous functions](#chain-asynchronous-functions) * [Compose functions](#compose-functions) * [Curry](#curry) +* [Log function name](#log-function-name) * [Pipe functions](#pipe-functions) * [Promisify](#promisify) * [Run promises in series](#run-promises-in-series) @@ -78,8 +80,11 @@ * [Fibonacci array generator](#fibonacci-array-generator) * [Greatest common divisor (GCD)](#greatest-common-divisor-gcd) * [Hamming distance](#hamming-distance) +* [Least common multiple (LCM)](#least-common-multiple-lcm) * [Percentile](#percentile) * [Powerset](#powerset) +* [Random integer in range](#random-integer-in-range) +* [Random number in range](#random-number-in-range) * [Round number to n digits](#round-number-to-n-digits) * [Standard deviation](#standard-deviation) @@ -101,6 +106,8 @@ * [Capitalize first letter of every word](#capitalize-first-letter-of-every-word) * [Capitalize first letter](#capitalize-first-letter) * [Check for palindrome](#check-for-palindrome) +* [Convert string from camelcase](#convert-string-from-camelcase) +* [Convert string to camelcase](#convert-string-to-camelcase) * [Reverse a string](#reverse-a-string) * [Sort characters in string (alphabetical)](#sort-characters-in-string-alphabetical) * [Truncate a string](#truncate-a-string) @@ -119,48 +126,21 @@ * [Measure time taken by function](#measure-time-taken-by-function) * [Number to array of digits](#number-to-array-of-digits) * [Ordinal suffix of number](#ordinal-suffix-of-number) -* [Random integer in range](#random-integer-in-range) -* [Random number in range](#random-number-in-range) * [RGB to hexadecimal](#rgb-to-hexadecimal) * [URL parameters](#url-parameters) * [UUID generator](#uuid-generator) * [Validate email](#validate-email) * [Validate number](#validate-number) -* [Value or default](#value-or-default) ## Array -### Array concatenation - -Use Array spread operators (`...`) to concatenate an array with any additional arrays and/or values, specified in `args`. - -```js -const ArrayConcat = (arr, ...args) => [...arr,...args]; -// ArrayConcat([1], [1, 2, 3, [4]]) -> [1, 1, 2, 3, [4]] -``` - -[⬆ back to top](#table-of-contents) - ### Array difference Create a `Set` from `b`, then use `Array.filter()` on `a` to only keep values not contained in `b`. ```js const difference = (a, b) => { const s = new Set(b); return a.filter(x => !s.has(x)); }; -// difference([1,2,3], [1,2]) -> [3] -``` - -[⬆ back to top](#table-of-contents) - -### Array includes - -Use `slice()` to offset the array/string and `indexOf()` to check if the value is included. -Omit the last argument, `fromIndex`, to check the whole array/string. - -```js -const includes = (collection, val, fromIndex=0) => collection.slice(fromIndex).indexOf(val) != -1; -// includes("30-seconds-of-code", "code") -> true -// includes([1, 2, 3, 4], [1, 2], 1) -> false +// difference([1,2,3], [1,2,4]) -> [3] ``` [⬆ back to top](#table-of-contents) @@ -176,6 +156,23 @@ const intersection = (a, b) => { const s = new Set(b); return a.filter(x => s.ha [⬆ back to top](#table-of-contents) +### Array pull (mutates array) + +Use `Array.filter()` and `Array.includes()` to pull out the values that are not needed. +Use `Array.length = 0` to mutate the passed in array by resetting it's length to zero and `Array.push()` to re-populate it with only the pulled values. + +```js +const pull = (arr, ...args) => { + let pulled = arr.filter((v, i) => !args.includes(v)); + arr.length = 0; pulled.forEach(v => arr.push(v)); +}; +// let myArray = ['a', 'b', 'c', 'a', 'b', 'c']; +// pull(myArray, 'a', 'c'); +// console.log(myArray) -> [ 'b', 'b' ] +``` + +[⬆ back to top](#table-of-contents) + ### Array remove Use `Array.filter()` to find array elements that return truthy values and `Array.reduce()` to remove elements using `Array.splice()`. @@ -187,7 +184,7 @@ const remove = (arr, func) => arr.splice(arr.indexOf(val), 1); return acc.concat(val); }, []) : []; -//remove([1, 2, 3, 4], n => n % 2 == 0) -> [2, 4] +// remove([1, 2, 3, 4], n => n % 2 == 0) -> [2, 4] ``` [⬆ back to top](#table-of-contents) @@ -204,6 +201,20 @@ const sample = arr => arr[Math.floor(Math.random() * arr.length)]; [⬆ back to top](#table-of-contents) +### Array symmetric difference + +Create a `Set` from each array, then use `Array.filter()` on each of them to only keep values not contained in the other. + +```js +const symmetricDifference = (a, b) => { + const sA = new Set(a), sB = new Set(b); + return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))]; +} +// symmetricDifference([1,2,3], [1,2,4]) -> [3,4] +``` + +[⬆ back to top](#table-of-contents) + ### Array union Create a `Set` with all values of `a` and `b` and convert to an array. @@ -276,7 +287,7 @@ const chunk = (arr, size) => Use `Array.filter()` to filter out falsey values (`false`, `null`, `0`, `""`, `undefined`, and `NaN`). ```js -const compact = (arr) => arr.filter(v => v); +const compact = (arr) => arr.filter(Boolean); // compact([0, 1, false, 2, '', 3, 'a', 'e'*23, NaN, 's', 34]) -> [ 1, 2, 3, 'a', 's', 34 ] ``` @@ -321,19 +332,6 @@ const dropElements = (arr, func) => { [⬆ back to top](#table-of-contents) -### Fill array - -Use `Array.map()` to map values between `start` (inclusive) and `end` (exclusive) to `value`. -Omit `start` to start at the first element and/or `end` to finish at the last. - -```js -const fillArray = (arr, value, start = 0, end = arr.length) => - arr.map((v, i) => i >= start && i < end ? value : v); -// fillArray([1,2,3,4],'8',1,3) -> [1,'8','8',4] -``` - -[⬆ back to top](#table-of-contents) - ### Filter out non-unique values in an array Use `Array.filter()` for an array containing only the unique values. @@ -458,10 +456,10 @@ const initializeArray = (n, value = 0) => Array(n).fill(value); ### Last of list -Use `arr.slice(-1)[0]` to get the last element of the given array. +Use `arr.length - 1` to compute index of the last element of the given array and returning it. ```js -const last = arr => arr.slice(-1)[0]; +const last = arr => arr[arr.length - 1]; // last([1,2,3]) -> 3 ``` @@ -607,7 +605,7 @@ const unique = arr => [...new Set(arr)]; Use `scrollY`, `scrollHeight` and `clientHeight` to determine if the bottom of the page is visible. ```js -const bottomVisible = _ => +const bottomVisible = () => document.documentElement.clientHeight + window.scrollY >= document.documentElement.scrollHeight || document.documentElement.clientHeight; // bottomVisible() -> true ``` @@ -619,7 +617,7 @@ const bottomVisible = _ => Use `window.location.href` to get current URL. ```js -const currentUrl = _ => window.location.href; +const currentUrl = () => window.location.href; // currentUrl() -> 'https://google.com' ``` @@ -680,7 +678,7 @@ Get distance from top using `document.documentElement.scrollTop` or `document.bo Scroll by a fraction of the distance from top. Use `window.requestAnimationFrame()` to animate the scrolling. ```js -const scrollToTop = _ => { +const scrollToTop = () => { const c = document.documentElement.scrollTop || document.body.scrollTop; if (c > 0) { window.requestAnimationFrame(scrollToTop); @@ -693,6 +691,19 @@ const scrollToTop = _ => { [⬆ back to top](#table-of-contents) ## Date +### Convert to English date + +Use `Date.toISOString()`, `split('T')` and `replace()` to convert a date from American format to English format. +Throws an error if the passed time cannot be converted to a date. + +```js +const toEnglishDate = (time) => + {try{return new Date(time).toISOString().split('T')[0].replace(/-/g, '/')}catch(e){return}}; +// toEnglishDate('09/21/2010') -> '21/09/2010' +``` + +[⬆ back to top](#table-of-contents) + ### Get days difference between dates Calculate the difference (in days) between to `Date` objects. @@ -702,6 +713,20 @@ const getDaysDiffBetweenDates = (dateInitial, dateFinal) => (dateFinal - dateIni // getDaysDiffBetweenDates(new Date("2017-12-13"), new Date("2017-12-22")) -> 9 ``` +[⬆ back to top](#table-of-contents) + +### JSON to date + +Use `Date()`, to convert dates in JSON format to readable format (`dd/mm/yyyy`). + +```js +const jsonToDate = arr => { + const dt = new Date(parseInt(arr.toString().substr(6))); + return `${ dt.getDate() }/${ dt.getMonth() + 1 }/${ dt.getFullYear() }` +}; +// jsonToDate(/Date(1489525200000)/) -> "14/3/2017" +``` + [⬆ back to top](#table-of-contents) ## Function @@ -736,6 +761,7 @@ const multiplyAndAdd5 = compose(add5, multiply) multiplyAndAdd5(5, 2) -> 15 */ ``` + [⬆ back to top](#table-of-contents) ### Curry @@ -756,6 +782,17 @@ const curry = (fn, arity = fn.length, ...args) => [⬆ back to top](#table-of-contents) +### Log function name + +Use `console.debug()` and the `name` property of the passed method to log the method's name to the `debug` channel of the console. + +```js +const functionName = fn => (console.debug(fn.name), fn); +// functionName(Math.max) -> max (logged in debug channel of console) +``` + +[⬆ back to top](#table-of-contents) + ### Pipe functions Use `Array.reduce()` with the spread operator (`...`) to perform left-to-right function composition. @@ -874,9 +911,12 @@ const isEven = num => num % 2 === 0; Use recursion. If `n` is less than or equal to `1`, return `1`. Otherwise, return the product of `n` and the factorial of `n - 1`. +Throws an exception if `n` is a negative number. ```js -const factorial = n => n <= 1 ? 1 : n * factorial(n - 1); +const factorial = n => + n < 0 ? (() => { throw new TypeError('Negative numbers are not allowed!') })() + : n <= 1 ? 1 : n * factorial(n - 1); // factorial(6) -> 720 ``` @@ -921,6 +961,21 @@ const hammingDistance = (num1, num2) => [⬆ back to top](#table-of-contents) +### Least common multiple (LCM) + +Use the greatest common divisor (GCD) formula and `Math.abs()` to determine the least common multiple. +The GCD formula uses recursion. + +```js +const lcm = (x,y) => { + const gcd = (x, y) => !y ? x : gcd(y, x % y); + return Math.abs(x*y)/(gcd(x,y)); +}; +// lcm(12,7) -> 84 +``` + +[⬆ back to top](#table-of-contents) + ### Percentile Use `Array.reduce()` to calculate how many numbers are below the value and how many are the same value and @@ -946,6 +1001,28 @@ const powerset = arr => [⬆ back to top](#table-of-contents) +### Random integer in range + +Use `Math.random()` to generate a random number and map it to the desired range, using `Math.floor()` to make it an integer. + +```js +const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; +// randomIntegerInRange(0, 5) -> 2 +``` + +[⬆ back to top](#table-of-contents) + +### Random number in range + +Use `Math.random()` to generate a random value, map it to the desired range using multiplication. + +```js +const randomInRange = (min, max) => Math.random() * (max - min) + min; +// randomInRange(2,10) -> 6.0211363285087005 +``` + +[⬆ back to top](#table-of-contents) + ### Round number to n digits Use `Math.round()` and template literals to round the number to the specified number of digits. @@ -981,7 +1058,7 @@ const standardDeviation = (arr, usePopulation = false) => { ### Speech synthesis (experimental) -Use `SpeechSynthesisUtterance.voice` and `indow.speechSynthesis.getVoices()` to convert a message to speech. +Use `SpeechSynthesisUtterance.voice` and `window.speechSynthesis.getVoices()` to convert a message to speech. Use `window.speechSynthesis.speak()` to play the message. Learn more about the [SpeechSynthesisUtterance interface of the Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance). @@ -1153,6 +1230,37 @@ const palindrome = str => { [⬆ back to top](#table-of-contents) +### Convert string from camelcase + +Use `replace()` to remove underscores, hyphens and spaces and convert words to camelcase. +Omit the scond argument to use a default separator of '_'. + +```js +const fromCamelCase = (str, separator = '_') => + str.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2') + .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2').toLowerCase(); +// fromCamelCase('someDatabaseFieldName', ' ') -> 'some database field name' +// fromCamelCase('someLabelThatNeedsToBeCamelized', '-') -> 'some-label-that-needs-to-be-camelized' +// fromCamelCase('someJavascriptProperty', '_') -> 'some_javascript_property' +``` + +[⬆ back to top](#table-of-contents) + +### Convert string to camelcase + +Use `replace()` to remove underscores, hyphens and spaces and convert words to camelcase. + +```js +const toCamelCase = str => + str.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2, offset) => p2 ? p2.toUpperCase() : p1.toLowerCase()); +// toCamelCase("some_database_field_name") -> 'someDatabaseFieldName' +// toCamelCase("Some label that needs to be camelized") -> 'someLabelThatNeedsToBeCamelized' +// toCamelCase("some-javascript-property") -> 'someJavascriptProperty' +// toCamelCase("some-mixed_string with spaces_underscores-and-hyphens") -> 'someMixedStringWithSpacesUnderscoresAndHyphens' +``` + +[⬆ back to top](#table-of-contents) + ### Reverse a string Use array destructuring and `Array.reverse()` to reverse the order of the characters in the string. @@ -1193,12 +1301,11 @@ const truncate = (str, num) => ### 3-digit hexcode to 6-digit hexcode -Use `Array.map()`, `split()` and `Array.join()` to join the mapped array for converting a three-digit RGB notated hexadecimal colorcode to the six-digit form. - +Use `Array.map()`, `split()` and `Array.join()` to join the mapped array for converting a three-digit RGB notated hexadecimal color-code to the six-digit form. +`Array.slice()` is used to remove `#` from string start since it's added once. ```js const convertHex = shortHex => - shortHex[0] == '#' ? ('#' + shortHex.slice(1).split('').map(x => x+x).join('')) : - ('#' + shortHex.split('').map(x => x+x).join('')); + '#' + shortHex.slice(shortHex.startsWith('#') ? 1 : 0).split().map(x => x+x).join() // convertHex('#03f') -> '#0033ff' // convertHex('05a') -> '#0055aa' ``` @@ -1230,11 +1337,14 @@ const getType = v => ### Hexcode to RGB -Use `Array.slice()`, `Array.map()` and `match()` to convert a hexadecimal colorcode (prefixed with `#`) to a string with the RGB values. +Use bitwise right-shift operator and mask bits with `&` (and) operator to convert a hexadecimal color code (prefixed with `#`) to a string with the RGB values. ```js -const hexToRgb = hex => `rgb(${hex.slice(1).match(/.{2}/g).map(x => parseInt(x, 16)).join()})` -// hexToRgb('#27ae60') -> 'rgb(39,174,96)' +const hexToRgb = hex => { + const h = parseInt(hex.slice(1), 16); + return `rgb(${h >> 16}, ${(h & 0x00ff00) >> 8}, ${h & 0x0000ff})`; +} +// hexToRgb('#27ae60') -> 'rgb(39, 174, 96)' ``` [⬆ back to top](#table-of-contents) @@ -1330,11 +1440,11 @@ const timeTaken = callback => { ### Number to array of digits -Convert the number to a string, use `split()` to convert build an array. +Convert the number to a string, using spread operators in ES6(`[...string]`) build an array. Use `Array.map()` and `parseInt()` to transform each value to an integer. ```js -const digitize = n => (''+n).split('').map(i => parseInt(i)); +const digitize = n => [...''+n].map(i => parseInt(i)); // digitize(2334) -> [2, 3, 3, 4] ``` @@ -1358,28 +1468,6 @@ const toOrdinalSuffix = num => { [⬆ back to top](#table-of-contents) -### Random integer in range - -Use `Math.random()` to generate a random number and map it to the desired range, using `Math.floor()` to make it an integer. - -```js -const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; -// randomIntegerInRange(0, 5) -> 2 -``` - -[⬆ back to top](#table-of-contents) - -### Random number in range - -Use `Math.random()` to generate a random value, map it to the desired range using multiplication. - -```js -const randomInRange = (min, max) => Math.random() * (max - min) + min; -// randomInRange(2,10) -> 6.0211363285087005 -``` - -[⬆ back to top](#table-of-contents) - ### RGB to hexadecimal Convert given RGB parameters to hexadecimal string using bitwise left-shift operator (`<<`) and `toString(16)`, then `padStart(6,'0')` to get a 6-digit hexadecimal value. @@ -1411,7 +1499,7 @@ const getUrlParameters = url => Use `crypto` API to generate a UUID, compliant with [RFC4122](https://www.ietf.org/rfc/rfc4122.txt) version 4. ```js -const uuid = _ => +const uuid = () => ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); @@ -1446,17 +1534,6 @@ const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == [⬆ back to top](#table-of-contents) -### Value or default - -Returns value, or default value if passed value is `falsy`. - -```js -const valueOrDefault = (value, d) => value || d; -// valueOrDefault(NaN, 30) -> 30 -``` - -[⬆ back to top](#table-of-contents) - ## Credits *Icons made by [Smashicons](https://www.flaticon.com/authors/smashicons) from [www.flaticon.com](https://www.flaticon.com/) is licensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/).* diff --git a/scripts/lint-script.js b/scripts/lint-script.js index 5d6d8721e..4aaa7c240 100644 --- a/scripts/lint-script.js +++ b/scripts/lint-script.js @@ -1,6 +1,7 @@ /* This is the linter script that lints snippets. Run using `npm run linter`. + You might have to run `npm i -g semistandard` for this script to run properly. */ // Load modules const fs = require('fs-extra'), cp = require('child_process'), path = require('path'), chalk = require('chalk'); diff --git a/snippets/3-digit-hexcode-to-6-digit-hexcode.md b/snippets/3-digit-hexcode-to-6-digit-hexcode.md index a138b34bb..3c1c87261 100644 --- a/snippets/3-digit-hexcode-to-6-digit-hexcode.md +++ b/snippets/3-digit-hexcode-to-6-digit-hexcode.md @@ -1,11 +1,10 @@ ### 3-digit hexcode to 6-digit hexcode -Use `Array.map()`, `split()` and `Array.join()` to join the mapped array for converting a three-digit RGB notated hexadecimal colorcode to the six-digit form. - +Use `Array.map()`, `split()` and `Array.join()` to join the mapped array for converting a three-digit RGB notated hexadecimal color-code to the six-digit form. +`Array.slice()` is used to remove `#` from string start since it's added once. ```js const convertHex = shortHex => - shortHex[0] == '#' ? ('#' + shortHex.slice(1).split('').map(x => x+x).join('')) : - ('#' + shortHex.split('').map(x => x+x).join('')); + '#' + shortHex.slice(shortHex.startsWith('#') ? 1 : 0).split().map(x => x+x).join() // convertHex('#03f') -> '#0033ff' // convertHex('05a') -> '#0055aa' ``` diff --git a/snippets/UUID-generator.md b/snippets/UUID-generator.md index 01d4e27ac..342fce12b 100644 --- a/snippets/UUID-generator.md +++ b/snippets/UUID-generator.md @@ -3,7 +3,7 @@ Use `crypto` API to generate a UUID, compliant with [RFC4122](https://www.ietf.org/rfc/rfc4122.txt) version 4. ```js -const uuid = _ => +const uuid = () => ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); diff --git a/snippets/array-concatenation.md b/snippets/array-concatenation.md deleted file mode 100644 index 4c337c9e9..000000000 --- a/snippets/array-concatenation.md +++ /dev/null @@ -1,8 +0,0 @@ -### Array concatenation - -Use Array spread operators (`...`) to concatenate an array with any additional arrays and/or values, specified in `args`. - -```js -const ArrayConcat = (arr, ...args) => [...arr,...args]; -// ArrayConcat([1], [1, 2, 3, [4]]) -> [1, 1, 2, 3, [4]] -``` diff --git a/snippets/array-difference.md b/snippets/array-difference.md index 208cb811e..defd82d6f 100644 --- a/snippets/array-difference.md +++ b/snippets/array-difference.md @@ -4,5 +4,5 @@ Create a `Set` from `b`, then use `Array.filter()` on `a` to only keep values no ```js const difference = (a, b) => { const s = new Set(b); return a.filter(x => !s.has(x)); }; -// difference([1,2,3], [1,2]) -> [3] +// difference([1,2,3], [1,2,4]) -> [3] ``` diff --git a/snippets/array-includes.md b/snippets/array-includes.md deleted file mode 100644 index 5ebcbc009..000000000 --- a/snippets/array-includes.md +++ /dev/null @@ -1,10 +0,0 @@ -### Array includes - -Use `slice()` to offset the array/string and `indexOf()` to check if the value is included. -Omit the last argument, `fromIndex`, to check the whole array/string. - -```js -const includes = (collection, val, fromIndex=0) => collection.slice(fromIndex).indexOf(val) != -1; -// includes("30-seconds-of-code", "code") -> true -// includes([1, 2, 3, 4], [1, 2], 1) -> false -``` diff --git a/snippets/array-pull-(mutates-array).md b/snippets/array-pull-(mutates-array).md new file mode 100644 index 000000000..d20e21c5e --- /dev/null +++ b/snippets/array-pull-(mutates-array).md @@ -0,0 +1,14 @@ +### Array pull (mutates array) + +Use `Array.filter()` and `Array.includes()` to pull out the values that are not needed. +Use `Array.length = 0` to mutate the passed in array by resetting it's length to zero and `Array.push()` to re-populate it with only the pulled values. + +```js +const pull = (arr, ...args) => { + let pulled = arr.filter((v, i) => !args.includes(v)); + arr.length = 0; pulled.forEach(v => arr.push(v)); +}; +// let myArray = ['a', 'b', 'c', 'a', 'b', 'c']; +// pull(myArray, 'a', 'c'); +// console.log(myArray) -> [ 'b', 'b' ] +``` diff --git a/snippets/array-remove.md b/snippets/array-remove.md index e08a4a02f..df2a83867 100644 --- a/snippets/array-remove.md +++ b/snippets/array-remove.md @@ -9,5 +9,5 @@ const remove = (arr, func) => arr.splice(arr.indexOf(val), 1); return acc.concat(val); }, []) : []; -//remove([1, 2, 3, 4], n => n % 2 == 0) -> [2, 4] +// remove([1, 2, 3, 4], n => n % 2 == 0) -> [2, 4] ``` diff --git a/snippets/array-symmetric-difference.md b/snippets/array-symmetric-difference.md new file mode 100644 index 000000000..7d178cd15 --- /dev/null +++ b/snippets/array-symmetric-difference.md @@ -0,0 +1,11 @@ +### Array symmetric difference + +Create a `Set` from each array, then use `Array.filter()` on each of them to only keep values not contained in the other. + +```js +const symmetricDifference = (a, b) => { + const sA = new Set(a), sB = new Set(b); + return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))]; +} +// symmetricDifference([1,2,3], [1,2,4]) -> [3,4] +``` diff --git a/snippets/bottom-visible.md b/snippets/bottom-visible.md index b94ac773a..797b0eb00 100644 --- a/snippets/bottom-visible.md +++ b/snippets/bottom-visible.md @@ -3,7 +3,7 @@ Use `scrollY`, `scrollHeight` and `clientHeight` to determine if the bottom of the page is visible. ```js -const bottomVisible = _ => +const bottomVisible = () => document.documentElement.clientHeight + window.scrollY >= document.documentElement.scrollHeight || document.documentElement.clientHeight; // bottomVisible() -> true ``` diff --git a/snippets/compact.md b/snippets/compact.md index 607634b4a..121d79bae 100644 --- a/snippets/compact.md +++ b/snippets/compact.md @@ -3,6 +3,6 @@ Use `Array.filter()` to filter out falsey values (`false`, `null`, `0`, `""`, `undefined`, and `NaN`). ```js -const compact = (arr) => arr.filter(v => v); +const compact = (arr) => arr.filter(Boolean); // compact([0, 1, false, 2, '', 3, 'a', 'e'*23, NaN, 's', 34]) -> [ 1, 2, 3, 'a', 's', 34 ] ``` diff --git a/snippets/compose-functions.md b/snippets/compose-functions.md index d61c9f3b6..4c7248930 100644 --- a/snippets/compose-functions.md +++ b/snippets/compose-functions.md @@ -11,4 +11,4 @@ const multiply = (x, y) => x * y const multiplyAndAdd5 = compose(add5, multiply) multiplyAndAdd5(5, 2) -> 15 */ -``` \ No newline at end of file +``` diff --git a/snippets/convert-string-from-camelcase.md b/snippets/convert-string-from-camelcase.md new file mode 100644 index 000000000..d9f2bacd6 --- /dev/null +++ b/snippets/convert-string-from-camelcase.md @@ -0,0 +1,13 @@ +### Convert string from camelcase + +Use `replace()` to remove underscores, hyphens and spaces and convert words to camelcase. +Omit the scond argument to use a default separator of '_'. + +```js +const fromCamelCase = (str, separator = '_') => + str.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2') + .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2').toLowerCase(); +// fromCamelCase('someDatabaseFieldName', ' ') -> 'some database field name' +// fromCamelCase('someLabelThatNeedsToBeCamelized', '-') -> 'some-label-that-needs-to-be-camelized' +// fromCamelCase('someJavascriptProperty', '_') -> 'some_javascript_property' +``` diff --git a/snippets/convert-string-to-camelcase.md b/snippets/convert-string-to-camelcase.md new file mode 100644 index 000000000..f59d213ae --- /dev/null +++ b/snippets/convert-string-to-camelcase.md @@ -0,0 +1,12 @@ +### Convert string to camelcase + +Use `replace()` to remove underscores, hyphens and spaces and convert words to camelcase. + +```js +const toCamelCase = str => + str.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2, offset) => p2 ? p2.toUpperCase() : p1.toLowerCase()); +// toCamelCase("some_database_field_name") -> 'someDatabaseFieldName' +// toCamelCase("Some label that needs to be camelized") -> 'someLabelThatNeedsToBeCamelized' +// toCamelCase("some-javascript-property") -> 'someJavascriptProperty' +// toCamelCase("some-mixed_string with spaces_underscores-and-hyphens") -> 'someMixedStringWithSpacesUnderscoresAndHyphens' +``` diff --git a/snippets/convert-to-english-date.md b/snippets/convert-to-english-date.md new file mode 100644 index 000000000..01a93cdf5 --- /dev/null +++ b/snippets/convert-to-english-date.md @@ -0,0 +1,10 @@ +### Convert to English date + +Use `Date.toISOString()`, `split('T')` and `replace()` to convert a date from American format to English format. +Throws an error if the passed time cannot be converted to a date. + +```js +const toEnglishDate = (time) => + {try{return new Date(time).toISOString().split('T')[0].replace(/-/g, '/')}catch(e){return}}; +// toEnglishDate('09/21/2010') -> '21/09/2010' +``` diff --git a/snippets/current-URL.md b/snippets/current-URL.md index 200cf150b..3a549d219 100644 --- a/snippets/current-URL.md +++ b/snippets/current-URL.md @@ -3,6 +3,6 @@ Use `window.location.href` to get current URL. ```js -const currentUrl = _ => window.location.href; +const currentUrl = () => window.location.href; // currentUrl() -> 'https://google.com' ``` diff --git a/snippets/factorial.md b/snippets/factorial.md index 155b7229e..d881fe941 100644 --- a/snippets/factorial.md +++ b/snippets/factorial.md @@ -3,8 +3,11 @@ Use recursion. If `n` is less than or equal to `1`, return `1`. Otherwise, return the product of `n` and the factorial of `n - 1`. +Throws an exception if `n` is a negative number. ```js -const factorial = n => n <= 1 ? 1 : n * factorial(n - 1); +const factorial = n => + n < 0 ? (() => { throw new TypeError('Negative numbers are not allowed!') })() + : n <= 1 ? 1 : n * factorial(n - 1); // factorial(6) -> 720 ``` diff --git a/snippets/fill-array.md b/snippets/fill-array.md deleted file mode 100644 index a5da15483..000000000 --- a/snippets/fill-array.md +++ /dev/null @@ -1,10 +0,0 @@ -### Fill array - -Use `Array.map()` to map values between `start` (inclusive) and `end` (exclusive) to `value`. -Omit `start` to start at the first element and/or `end` to finish at the last. - -```js -const fillArray = (arr, value, start = 0, end = arr.length) => - arr.map((v, i) => i >= start && i < end ? value : v); -// fillArray([1,2,3,4],'8',1,3) -> [1,'8','8',4] -``` diff --git a/snippets/hexcode-to-RGB.md b/snippets/hexcode-to-RGB.md index 852a25ff8..2bb33480f 100644 --- a/snippets/hexcode-to-RGB.md +++ b/snippets/hexcode-to-RGB.md @@ -1,8 +1,11 @@ ### Hexcode to RGB -Use `Array.slice()`, `Array.map()` and `match()` to convert a hexadecimal colorcode (prefixed with `#`) to a string with the RGB values. +Use bitwise right-shift operator and mask bits with `&` (and) operator to convert a hexadecimal color code (prefixed with `#`) to a string with the RGB values. ```js -const hexToRgb = hex => `rgb(${hex.slice(1).match(/.{2}/g).map(x => parseInt(x, 16)).join()})` -// hexToRgb('#27ae60') -> 'rgb(39,174,96)' +const hexToRgb = hex => { + const h = parseInt(hex.slice(1), 16); + return `rgb(${h >> 16}, ${(h & 0x00ff00) >> 8}, ${h & 0x0000ff})`; +} +// hexToRgb('#27ae60') -> 'rgb(39, 174, 96)' ``` diff --git a/snippets/last-of-list.md b/snippets/last-of-list.md index d27b0b35e..b4729b152 100644 --- a/snippets/last-of-list.md +++ b/snippets/last-of-list.md @@ -1,8 +1,8 @@ ### Last of list -Use `arr.slice(-1)[0]` to get the last element of the given array. +Use `arr.length - 1` to compute index of the last element of the given array and returning it. ```js -const last = arr => arr.slice(-1)[0]; +const last = arr => arr[arr.length - 1]; // last([1,2,3]) -> 3 ``` diff --git a/snippets/least-common-multiple-(LCM).md b/snippets/least-common-multiple-(LCM).md new file mode 100644 index 000000000..4f3fc2822 --- /dev/null +++ b/snippets/least-common-multiple-(LCM).md @@ -0,0 +1,12 @@ +### Least common multiple (LCM) + +Use the greatest common divisor (GCD) formula and `Math.abs()` to determine the least common multiple. +The GCD formula uses recursion. + +```js +const lcm = (x,y) => { + const gcd = (x, y) => !y ? x : gcd(y, x % y); + return Math.abs(x*y)/(gcd(x,y)); +}; +// lcm(12,7) -> 84 +``` diff --git a/snippets/log-function-name.md b/snippets/log-function-name.md new file mode 100644 index 000000000..b449331f8 --- /dev/null +++ b/snippets/log-function-name.md @@ -0,0 +1,8 @@ +### Log function name + +Use `console.debug()` and the `name` property of the passed method to log the method's name to the `debug` channel of the console. + +```js +const functionName = fn => (console.debug(fn.name), fn); +// functionName(Math.max) -> max (logged in debug channel of console) +``` diff --git a/snippets/number-to-array-of-digits.md b/snippets/number-to-array-of-digits.md index f00a62b75..3d8a3c0e0 100644 --- a/snippets/number-to-array-of-digits.md +++ b/snippets/number-to-array-of-digits.md @@ -1,9 +1,9 @@ ### Number to array of digits -Convert the number to a string, use `split()` to convert build an array. +Convert the number to a string, using spread operators in ES6(`[...string]`) build an array. Use `Array.map()` and `parseInt()` to transform each value to an integer. ```js -const digitize = n => (''+n).split('').map(i => parseInt(i)); +const digitize = n => [...''+n].map(i => parseInt(i)); // digitize(2334) -> [2, 3, 3, 4] ``` diff --git a/snippets/scroll-to-top.md b/snippets/scroll-to-top.md index 6c82190a4..19064a5d5 100644 --- a/snippets/scroll-to-top.md +++ b/snippets/scroll-to-top.md @@ -4,7 +4,7 @@ Get distance from top using `document.documentElement.scrollTop` or `document.bo Scroll by a fraction of the distance from top. Use `window.requestAnimationFrame()` to animate the scrolling. ```js -const scrollToTop = _ => { +const scrollToTop = () => { const c = document.documentElement.scrollTop || document.body.scrollTop; if (c > 0) { window.requestAnimationFrame(scrollToTop); diff --git a/snippets/speech-synthesis-(experimental).md b/snippets/speech-synthesis-(experimental).md index c9e6a288c..2a5cb1d20 100644 --- a/snippets/speech-synthesis-(experimental).md +++ b/snippets/speech-synthesis-(experimental).md @@ -1,6 +1,6 @@ ### Speech synthesis (experimental) -Use `SpeechSynthesisUtterance.voice` and `indow.speechSynthesis.getVoices()` to convert a message to speech. +Use `SpeechSynthesisUtterance.voice` and `window.speechSynthesis.getVoices()` to convert a message to speech. Use `window.speechSynthesis.speak()` to play the message. Learn more about the [SpeechSynthesisUtterance interface of the Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance). diff --git a/snippets/value-or-default.md b/snippets/value-or-default.md deleted file mode 100644 index 0af9529e8..000000000 --- a/snippets/value-or-default.md +++ /dev/null @@ -1,8 +0,0 @@ -### Value or default - -Returns value, or default value if passed value is `falsy`. - -```js -const valueOrDefault = (value, d) => value || d; -// valueOrDefault(NaN, 30) -> 30 -``` diff --git a/tag_database b/tag_database index 9f1b18f46..56a50f864 100644 --- a/tag_database +++ b/tag_database @@ -1,11 +1,11 @@ 3-digit-hexcode-to-6-digit-hexcode:utility anagrams-of-string-(with-duplicates):string -array-concatenation:array array-difference:array -array-includes:array array-intersection:array +array-pull-(mutates-array):array array-remove:array array-sample:array +array-symmetric-difference:array array-union:array array-without:array array-zip:array @@ -20,6 +20,9 @@ clean-JSON-object:object collatz-algorithm:math compact:array compose-functions:function +convert-string-from-camelcase:string +convert-string-to-camelcase:string +convert-to-english-date:date count-occurrences-of-a-value-in-array:array current-URL:browser curry:function @@ -32,7 +35,6 @@ escape-regular-expression:utility even-or-odd-number:math factorial:math fibonacci-array-generator:math -fill-array:array filter-out-non-unique-values-in-an-array:array flatten-array-up-to-depth:array flatten-array:array @@ -55,7 +57,10 @@ is-function:utility is-number:utility is-string:utility is-symbol:utility +JSON-to-date:date last-of-list:array +least-common-multiple-(LCM):math +log-function-name:function measure-time-taken-by-function:utility median-of-array-of-numbers:array nth-element-of-array:array @@ -68,8 +73,8 @@ pick:array pipe-functions:function powerset:math promisify:function -random-integer-in-range:utility -random-number-in-range:utility +random-integer-in-range:math +random-number-in-range:math read-file-as-array-of-lines:node redirect-to-URL:browser reverse-a-string:string @@ -95,5 +100,4 @@ URL-parameters:utility UUID-generator:utility validate-email:utility validate-number:utility -value-or-default:utility write-JSON-to-file:node