The challenge:
Write a function that takes in a string of one or more words, and returns the same string, but with all five or more letter words reversed (Just like the name of this Kata). Strings passed in will consist of only letters and spaces. Spaces will be included only when more than one word is present.
Example:
spinWords( "Hey fellow warriors" ) => returns "Hey wollef sroirraw"
At the moment I have this
function spinWords(str) {
var splitArray = str.split(' ')
for (var i = 0; i < splitArray.length; i++) {
if (splitArray[i].length > 5) {
var long = splitArray[i].split('').reverse('').join('')
return long
i++
} else {
var short = splitArray[i]
return short
i++
}
}
}
As I said in the title, this is working properly but will only return the first element in the array as reversed or not. Can anyone smarter than me please explain why the loop is not looping?
Thank you for your time.
Return ends the function.
Another approach.
const spinWords = words =>
words
.split(" ")
.map(word => (word.length >= 5 ? [...word].reverse().join("") : word))
.join(" ");
console.log(spinWords("Hey fellow warriors"));
you are almost there..
using for loop, you do not want to do another i++..
you said that it would be 5 or more.. so it should be >=5
return terminates the for loop, so use it last..
the modified function can look like this:
function spinWords(str){
var splitArray = str.split(' ');
var spinnedWords = '';
for (var i = 0; i < splitArray.length; i++) {
if (splitArray[i].length >= 5) {
var long = splitArray[i].split('').reverse('').join('');
spinnedWords = spinnedWords.concat(' ' + long);
}
else {
var short = splitArray[i]
spinnedWords = spinnedWords.concat(' ' + short);
}
}
return spinnedWords.trim();
}
Three things must be changed for this code to work properly.
First
The return statement will finish the entire function execution. So it should be placed at the end of the body when no more code will be executed.
Second
You can switch the values you are iterating over and then return the same array with the inverted operation of the first line (.join(' ')).
Third
The for loop already increment the index counter at the end of each iteration if you defined it in the parameters. You don't need i++ inside the loop body.
function spinWords(str) {
var splitArray = str.split(' ');
for (var i = 0; i < splitArray.length; i++) {
if (splitArray[i].length >= 5) {
var long = splitArray[i]
.split('')
.reverse('')
.join('');
splitArray[i] = long;
}
}
return splitArray.join(' ')
}
EDIT: There's no need for else statement
EDIT2: I forgot the third change needed
function spinWords(str) {
return str
.split(" ")
.map(word => word.length >= 5 ? word.split("").reverse().join("") : word)
.join(" ");
}
console.log( spinWords("Hey fellow warriors") );
This is my answer after your tips:
function spinWords(str){
var splitArray = str.split(' ')
var finalArray = []
for (var i = 0; i < splitArray.length; i++) {
if (splitArray[i].length >= 5) {
var long = splitArray[i].split('').reverse('').join('')
finalArray.push(long)
}
else {
var short = splitArray[i]
finalArray.push(short)
}
}
return finalArray.join(' ')
}
Related
I'm solving a simple problem where I need to capitalize the first alphabet of all words. I was able to do that but I have another string vn52tqsd0e4a if any of my output is matched with this string I have to replace it with --[matched string]-- .
so the expected output should be H--e--llo Worl--d--
but when I'm trying to replace the element with -- it's not doing anything. I tried replace() method as well but it didn't work. I don't know what I'm doing wrong here.
function LetterCapitalize(str) {
// code goes here
let array = str.split(" ")
for (let i=0; i<array.length; i++){
array[i] = array[i].charAt(0).toUpperCase() + array[i].slice(1)
}
let output = array.join(" ") ;
let comp = "vn52tqsd0e4a".split("");
for (let i=0; i<output.length; i++){
comp.map(el=> {
if(output[i] === el){
console.log( `matched ${output[i]}` )
output[i] = `--${output[i]}--`;
console.log(output[i]);
}
})
//
}
console.log(output);
}
LetterCapitalize("hello world");
You can achieve this using split, map, join as:
function LetterCapitalize(str) {
// code goes here
let array = str.split(' ');
for (let i = 0; i < array.length; i++) {
array[i] = array[i].charAt(0).toUpperCase() + array[i].slice(1);
}
let output = array.join(' ');
let comp = 'vn52tqsd0e4a'.split('');
const result = output
.split('')
.map((c) => (comp.includes(c) ? `--${c}--` : c))
.join('');
console.log(result);
}
LetterCapitalize('hello world');
You coulduse Array.reduce() to iterate over the str argument and either capitalize or replace depending on the character.
If the preceeding value is a space we'll capitalize, otherwise if the character is in the comp value, we'll replace with --${char}--.
function LetterCapitalize(str) {
const comp = "vn52tqsd0e4a";
return [...str].reduce((acc, char, idx, a) => {
if (idx === 0 || a[idx - 1] === ' ') {
char = char.toUpperCase();
} else if (comp.includes(char)) {
char = `--${char}--`;
}
return acc + char;
}, '')
}
console.log(LetterCapitalize("hello world"));
console.log(LetterCapitalize("hey man"));
What you say to JavaScript in the piece of code is that it should fit 5 characters in a place that can only hold one character.
output[i] = `--${output[i]}--`;
You need to change it to something like this (code below may not work):
output = output.substring(0,i-1) + el + output.substring(i+1,output.length - i-1);
I recommend using the string.replaceAll function instead. If you create a loop yourself you'll get problems when adding more characters on a place where original one character was present.
function LetterCapitalize(str) {
// code goes here
let array = str.split(" ")
for (let i=0; i<array.length; i++){
array[i] = array[i].charAt(0).toUpperCase() + array[i].slice(1)
}
let output = array.join(" ") ;
let comp = "vn52tqsd0e4a".split("");
comp.map(el=> {
output = output.replaceAll(el, '--' + el + '--');
});
console.log(output);
}
LetterCapitalize("hello world");
I am trying to make this Pig Latin function (I just started coding 3 weeks ago, so go easy on me), and I can't figure out why I can't get the array made from .split(' ') and then iterated through to join back again. In the output I only get the first word. The code is below:
function pigLatin(str) {
let str1 = str.split(' ')
for (let i = 0; i < str1.length; i++) {
if (str1[i].length <= 1) {
return str1[i];
}
else {
let first = str1[i].substring(0,1);
let word = str1[i].substring(1);
str = word + first + 'ay';
return str
}
}
}
console.log(pigLatin("This is a test"));
Keep in mind that I was considering adding regex and more else if statements, but I can't even get this to work yet. Any help is greatly appreciated.
You're returning too early. You should be adding each word to an array, and at the end of your loop you should concatenate the words in the array to form a new string which you should return. See my comments for how I altered your code:
function pigLatin(str) {
let r = [] // The array to build
let str1 = str.split(' ')
for (let i = 0; i < str1.length; i++) {
if (str1[i].length <= 1) {
r.push( str1[i] ); // Add to end of array
}
else {
let first = str1[i].substring(0,1);
let word = str1[i].substring(1);
str = word + first + 'ay';
r.push(str) // Add to end of array
}
}
return r.join(' ') // Join strings in array and return new string
}
console.log(pigLatin("This is a test"));
I've checked some similar questions but I don't feel like the answers apply directly to what I'm looking for.
I'm trying to find the word with the most vowels in a given string. I know how to split a string into words like this:
let words = string.split(" ");
And so far I have:
function mostVowels(string) {
let vowels = ["aeiouAEIOU"];
let words = string.split(" ");
//initiate vowel count at 0
let counter = 0;
//loop through words
for (let i = 0; i < words.length; i++) {
//if there are vowels in the word, add vowels to counter
if (vowels.includes(i)) {
counter++
}
}
return counter;
}
console.log(mostVowels("I went to the park today."));
So obviously I'm pretty far from reaching a solution.
Right now this is returning 0.
There's 1 vowel in each of the first five words in that string, and there are two vowels in "today", so ultimately we want for this function to return "today" as the word with the most vowels.
At this point I'm just trying to get a vowel count for the first word in the string - it should be 1.
Then I figure I'll be able to compare the counts of the different words to determine which count is the greatest.
Define your vowels to be an array of characters, rather than an array containing a single string. Then, inside the loop over words, initialize the counter to 0, and iterate over each character in the word. If the character is included in the vowels array, increment the counter. At the end of iterating over the word, if the counter for this word is better than the best counter so far, assign the counter and the word to outer variables, indicating the best word / counter so far. At the end of the function, return the best word:
function mostVowels(string) {
let vowels = [..."aeiouAEIOU"];
let words = string.split(" ");
let bestCounter = 0;
let bestWord;
for (let i = 0; i < words.length; i++) {
const word = words[i];
//initiate vowel count at 0
let counter = 0;
for (let i = 0; i < word.length; i++) {
const char = word[i];
//if there are vowels in the word, add vowels to counter
if (vowels.includes(char)) {
counter++
}
}
// finished iterating through loop,
// now check to see if it's better than the best word so far:
if (counter > bestCounter) {
bestCounter = counter;
bestWord = word;
}
}
return bestWord;
}
console.log(mostVowels("I went to the park today."));
console.log(mostVowels("I went to the fooaeuiubar park today."));
Or, perhaps more elegantly, using array methods instead:
const vowels = [..."aeiouAEIOU"];
const getVowelCount = word => [...word].reduce((a, char) => a + Boolean(vowels.includes(char)), 0);
function mostVowels(string) {
let bestCounter = 0;
return string.split(' ')
.reduce((bestWordSoFar, thisWord) => {
const thisVowelCount = getVowelCount(thisWord);
if (thisVowelCount > bestCounter) {
bestCounter = thisVowelCount;
return thisWord;
} else {
return bestWordSoFar;
}
});
}
console.log(mostVowels("I went to the park today."));
console.log(mostVowels("I went to the fooaeuiubar park today."));
I tried to approach this through map-reduce trying to keep things pure and clean. But I had to set mostVowels in reduce, making it a bit stupid.
But here's my shot:
const handleSentence = (sentence = '') => {
const vowels = /[a|e|i|o|u]+/gi;
const words = sentence.split(' ');
let mostVowels = '';
const getVowels = (str = '') => {
try {
return str.match(vowels).join('').length
} catch (err) {
return 0;
}
};
const getMostVowels = (a, b, i) => {
if (a < b) {
mostVowels = words[i];
return b;
}
return a;
}
words.map(getVowels).reduce(getMostVowels);
return mostVowels;
}
console.log(handleSentence('this is an example string for demonstrating the function'));
console.log(handleSentence('yet another example of the effectiveness of function'));
console.log(handleSentence('gypsy rhythm'));
One alternate is to use regex
let mostVowels = (input) =>{
let max = 0;
let splited = input.split(' ')
splited.forEach((e, index) => {
let count = (e.match(/[aeiou]/gi)||[]).length
max = count > max ? index : max
})
return splited[max]
}
console.log(mostVowels("I went to the park today."));
console.log(mostVowels("I went to the fooaeuiubar park today. xyz"));
A bit shorter alternative with sorting :
const vowels = s => s.split(/[aeiou]/i).length - 1;
const mostVowels = s => s.split(/\W/).sort((a, b) => vowels(b) - vowels(a))[0];
console.log( mostVowels("I went to the park today.") );
and without sorting :
const vowels = s => s.replace(/[^aeiou]/gi, '').length;
const mostVowels = s => s.split(/\W/).reduce((a, b) => vowels(a) > vowels(b) ? a : b);
console.log( mostVowels("I went to the park today.") );
I am writing a function to reverse only words in a string that are a certain length, in this case 5 or more. I can make each word reverse if it is that length, but I am having trouble returning the right words back to the string.
function spinWords(string){
let splitString = string.split(" ");
console.log(splitString);
splitString.forEach(function(word) {
if (word.length >= 5) {
console.log(word.split("").reverse().join(""));
return word.split("").reverse().join("");
} else if (word.length < 5) {
console.log(word);
return word;
}
//should something go here?
});
console.log(splitString); //returns same output as when called at top of function
newString = splitString.join(" ");
console.log(newString);
}
spinWords("Jammerson is the best friend ever");
Alternatively, When I save the forEach() function into a new variable, the function is returned as undefined. I'm not sure which piece I am missing. Thanks in advance!
First off, your function needs to return a value. Also, try creating another string that will have the new value:
function spinWords(string){
let newString = ''; // added this here
let splitString = string.split(" ");
splitString.forEach(function(word, index) {
if (word.length >= 5) {
newString += word.split("").reverse().join(""); // added this here
} else if (word.length < 5) {
newString += word; // added this here
}
// add a space between characters, unless its the last char
if(splitString.length > index + 1) {
newString += ' '; // added this here
}
});
return newString;
}
console.log(spinWords("Jammerson is the best friend ever"));
You just need a little fix:
function spinWords(string){
let splitString = string.split(" ");
console.log(splitString);
splitString.forEach(function (word, index, arr) {
if (word.length >= 5) {
console.log(word.split("").reverse().join(""));
arr[index] = word.split("").reverse().join("");
} else if (word.length < 5) {
console.log(word);
arr[index] = word;
}
//should something go here?
});
console.log(splitString); //returns same output as when called at top of function
newString = splitString.join(" ");
console.log(newString);
}
spinWords("Jammerson is the best friend ever");
Instead of only iterating the array with forEach you want to map it to a new array of reversed words:
splitString = splitString.map(function(word) {
then the returned words will be taken. That could be shortened to this oneliner:
const reverseWord = str => str.length >= 5 ? str.split``.reverse().join`` : str;
const spinWords = str => str.split` `.map(reverseWord).join` `;
Alright, so basically this code passes in a sentence into the function and the function needs to figure out which word is longest to return. Everything works great except that the very last letter keeps getting cut off. So what would be a good solution to this problem?
function LongestWord(sen) {
sen = sen.toLowerCase();
var build = "";
var arr = [];
var longest = 0;
for(var i = 0; i < sen.length;i++){
var cur = sen.charCodeAt(i);
console.log(sen.charCodeAt(i))
if(i == sen.length - 1){
arr.push(build);
}
if(sen.charAt(i) === " "){
arr.push(build);
build = "";
}
if(cur >= 97 && cur <= 122){
build += String.fromCharCode(cur);
}
}
console.log(arr);
for(var e = 0; e < arr.length - 1;e++){
if(arr[e].length > arr[e + 1].length){
longest = arr[e];
}
else{
longest = arr[e + 1];
}
}
return longest;
}
// keep this function call here
// to see how to enter arguments in JavaScript scroll down
console.log(LongestWord("Johnny ErsoL"));
It returns "Johnny", which is correct, but this is what the Array looks like at the end.
[ 'johnny', 'erso' ]
Here's my suggestion ?
function LongestWord(sen) {
return sen.split(/\b/).filter(function(item) {
return item.trim().length;
}).sort(function(a,b) {
return b.length - a.length;
});
}
split the sentence on word boundary, then trim off empty spaces, finally sort by length of each word and return the sorted array.
Try replacing
for(var i = 0; i < sen.length;i++){
var cur = sen.charCodeAt(i);
console.log(sen.charCodeAt(i))
if(i == sen.length - 1){
arr.push(build);
}
if(sen.charAt(i) === " "){
arr.push(build);
build = "";
}
if(cur >= 97 && cur <= 122){
build += String.fromCharCode(cur);
}
}
with
arr=sen.split();
You have a for loop with e <arr.length -1. I don't think you need the -1.
I know you already found your answer, however I just wanted to show you an alternative to what you are doing.
To simplify your code and also make it more understandable, but also flexible, it's usually a good idea to make sure that every function does only one thing, or has a single responsability.
In your code, your LongestWord function has the responsability to identify what is a word and to find out which one is the longest.
What you could have done is create a function that knows how to tokenize a sentence into words:
function forEachWordsIn(str, callback) {
var rx = /\b(\w+?)\b/g,
match;
while (match = rx.exec(str)) callback(match[0]);
}
Then use that words iterator function from the longestWord function, which makes this algorithm extremely trivial now:
function longestWord(sen) {
var longestWord = '';
forEachWordsIn(sen, function (word) {
if (word.length > longestWord.length) longestWord = word;
});
return longestWord;
}
Note: I renamed LongestWord to longestWord because making functions start with captital letters is a well known standard to identify constructor functions.