CoDEVIANT #11 (4/5/19)
Problem 1: Autocomplete! Yay!
Instructions:
It’s time to create an autocomplete function! Yay!
The autocomplete function will take in an input string and a dictionary array and return the values from the dictionary that start with the input string. If there are more than 5 matches, restrict your output to the first 5 results. If there are no matches, return an empty array.
Example:
autocomplete(‘ai’, [‘airplane’,’airport’,’apple’,’ball’]) = [‘airplane’,’airport’]
For this kata, the dictionary will always be a valid array of strings. Please return all results in the order given in the dictionary, even if they’re not always alphabetical. The search should NOT be case sensitive, but the case of the word should be preserved when it’s returned.
For example, “Apple” and “airport” would both return for an input of ‘a’. However, they should return as “Apple” and “airport” in their original cases.
Important note:
Any input that is NOT a letter should be treated as if it is not there. For example, an input of “$%^” should be treated as “” and an input of “ab*&1cd” should be treated as “abcd”.
(Thanks to wthit56 for the suggestion!)
How Adrian Solved It
function autocomplete(input, dictionary){let array = [];let regexRule = /[A-Z]/ig;input = input.match(regexRule).join(‘’);dictionary.forEach((word)=>{if(word.slice(0,input.length).toLowerCase() === input){if(array.length <=4){array.push(word);}}})return array;}
- I make an empty array…called array.
- I create a variable that contains a regex rule (which I called regexRule) which seeks for all alphabetical characters a through z globally (hence the g) which means it will catch all the matches, and with ignoring the case of the letter it encounters (hence the i).
- I make input equal itself after going through the string method .match( ) with the regexRule we created as an argument.
- This method (.match( ) ) creates an array, so I immediately chain the array method .join(‘’) onto it so that I can get a string.
- At this point, input is now free of any special characters.
- I use the .forEach( ) method on the argument we were passed called dictionary, an array with tons of words.
- Inside the method’s code block, I create an if statement where i seek that the word, truncated down to the length of the input with the use of .slice( ) a string method that returns portions of strings based on the arguments you pass into it [in our case I went from the beginning 0 to however long the input was input.length], AND made lowercase with .toLowerCase( ) equals what we have for input
- If that’s the case:
- If the array’s length is less then or equal to 4, we push word into the array.
- If that’s the case and array has a length of 5 OR if it’s not true
- Nothing happens
- We return array.
How the Best Practice Way to Do It Works:
function autocomplete(input, dictionary){var r = new RegExp(‘^’ + input.replace(/[^a-z]/gi,’’), ‘i’);return dictionary.filter(function(w){ return r.test(w); }).slice(0, 5);}
- We make a variable r which uses the RegEx symbol of the carrot ^ to denote the beginning of string the RegEx pattern will be used on. Then we concatenate the result of using the .replace( ) string method on input but we pass in a RegEx Expression and a pair of empty quotes. This is going to result in us getting the replace( ) method’s expression -> { a cocktail of getting from the very beginning the a-z alphabetical characters of input regardless of case (i for ignore-case), throughout the entire length of input (g for global), then we concatenate an ‘i’ at the end.
- The result is something like that that will be used in the next step of our function:
/^pu/i
This lets us hunt for things that start with ‘pu’ regardless of whether one or both of the characters are lowercase or not.
- Next we return the dictionary argument with the array method .filter( ) being run on it. It has a callback function of taking each element of dictionary and calling it w. then we return inside the function’s code block r testing the passed in w to see if it’s beginning characters match it. Then we slice this array that is being returned from the filter from 0 to 5.
What I’ve learned:
It’s better to use something sleek and simple like .filter( ) instead of lots of array manipulation and for-loops or if-statements. It’s getting a bit clearer to me now how that works and I’m going to really try to set that up in the future. I’m going to start looking back at my previous entries as I solve new problems and see if there are any commonalities that I can pick up on so I don’t keep doing the same thing over and over.
Later nerds, I literally am singing an opera right now.