Title Case a Sentence with nested Arrays [SOLVED]

Title Case a Sentence with nested Arrays [SOLVED]
0

#1

Howdy folks,

So, I’m in the Basic Algorithms section working on the ‘Title Case a Sentence’ project.

I decided to take a nested For Loop approach.

The steps in my brain go like this;

  1. Split the string into an array of words, make sure all characters are lower case. (stringArray)
  2. Split these words in to arrays of letters, so they become nested arrays of the stringArray (wordArray)
  3. Upper case the first letter of each word based on its index in wordArray.
  4. Join the words back together, now with the first letter capitalized.
  5. Join the string back together with a space between each word.

In its present state, it seems that my For Loops are being completely skipped over in the function and I can’t figure out why. That’s the part I could use help with at the moment.

Here’s the code:

function titleCase(str) {
  var stringArray = str.toLowerCase().split(' ');
  
  for (i = 0; i < stringArray.length; i++) {
    var wordArray = stringArray[i].split('');
    
    for (j = 0; j < wordArray.length; j++) {
      wordArray[j][0].toUpperCase();
      wordArray.join('');
    }
  }
  
  var titleCaseString = stringArray.join(' ');
  
  return titleCaseString;
}

titleCase("I'm a little tea pot");

#2

Well instead of creating two for loops and arrays you could just have one for loop and one array and use the string.replace and string.charAt function. You could just use the first for loop and instead of trying to split them again use those two functions to replace the first letter of the word and then join it all again.


#3

Thanks @the702guy, I did see solutions using that approach in some examples. While it’s definitely useful and I would likely take that approach in a real-world example, now that I’ve seen those methods used. I’ll agree it’s a more elegant and concise approach. But I felt like I wouldn’t really have learned much just copying another coder’s solution. I had’t seen one quite like the one I’m trying here, so I thought I’d have a go at it.


#4

So I figured it out using two for loops like you had. I have a solution if you would like me to post it. If you would like to figure it out yourself here are a few hints:

-Try defining your variables first.
-You will need to use methods such as push, shift, and unshift
-Your for loops will need to be separate, not nested into each other

Like I said I made a solution that works and I have already tested it. If you would like me to post it let me know. I hope these hints get you in the right direction.

EDIT: Also your wordArray variable is running the for loop and resulting in only the last word in the array actually being split up, not every word. You will need to use one of the methods I mentioned above to make arrays of those split words nested in to one array.


#5

Thanks so much for the hints! Much appreciated, @the702guy!

I’d like to have a go at figuring this out from your hints first before asking for more help. I’ll let you know the results hopefully soon.


#6

No worries man, I hope you get it! I have the solution saved in a pen so just let me know if you would like to see it, I’ll post it here.


#7

So I did finally come up with a solution I’m satisfied with this morning (got some help from a work colleague). It ended up only requiring one loop, however.

I was basically trying to create a nested array that allowed me to use toUpperCase() on the zero index of each word. I was thinking I would need two loops to do this, but it turned out not to be the case. I didn’t even need to use push, shift or unshift methods, so I feel like this turned out to be a pretty clean approach to the problem.

I also changed the nomenclature a little bit;
stringArray (array of words made from a string) has been changed to wordArray (array of words).
wordArray (array of characters made from words) has been changed to charArray (array of characters).

Seemed to make more intuitive sense after I had been looking at other examples for this problem.

I would love to see your two loop function, @the702guy, now that I was able to get through this.

Here’s mine:


SPOILER ALERT

function titleCase(str) {
  var wordArray = str.toLowerCase().split(' '); // changes string to all lower case and separates string into array of words
  // console.log(stringArray);
  var charArray = []; // creates array to be nested in upcoming loop
  
  for (i = 0; i < wordArray.length; i++) {
    charArray = wordArray[i].split(''); // creates nested array of individual characters
    // console.log(charArray[0].toUpperCase());
    charArray[0] = charArray[0].toUpperCase(); // changes first value of each nested array to upper case character
    // console.log(charArray.join(''));
    wordArray[i] = charArray.join(''); // joins nested character array back into word array
  }
  
  str = wordArray.join(' '); // joins word array back into string, with spaces separating each word
  
  // console.log(str);
  return str;
}

titleCase("I'm a little tea pot");

#8

I hope it is OK to chime in here. First of all, I too had originally had used an array and a for loop much as you did. Then, later I refactored using the reduce method to get the result with minimal code (see below).

function titleCase(str) {
  return str.split(' ').reduce( (words,word) => words.concat(word[0].toUpperCase() + word.slice(1).toLowerCase()),[]).join(' ');
}

But after reading through your post this morning, I asked myself if there was a way to take out at least one of the two array steps (split or join)? Of course there is and decided to take a completely different approach that still had one loop, but did not use arrays at all (see below). Let me know what you think. It passes all the tests and I think it basically does the same thing as the advanced solution on gitbhub without using a regular expression. Now I must create some really large strings to test out which is faster (regular expressions or not).

function titleCase(str) {
  var newStr = '';
  for (var i=0; i<str.length; i++) {
    if (str[i] !== ' ' && str[i-1] === ' ' || i===0) newStr += str[i].toUpperCase();
    else newStr += str[i].toLowerCase();
  }
  return newStr;
}

#9

Bloody 'ell, @rmdawson71, I’m impressed! Especially with your first example, all on one line.


#10

Thanks. That one liner was not my first approach. My first try used split, loop, and rejoin. I really wanted to make use of the higher order function reduce, so I thought about for a couple of days and implemented what I showed above. Lately, I try to come up with multiple ways of solving each challenge and then using time tests to see which is faster. I have come across some problems on other coding challenge sites where execution time is more important than an elegant solution (i.e. one liner).


#11

I think I’ll go ahead and mark this problem as [solved]. Thanks @rmdawson71 and @the702guy for your input.

@the702guy, I’d still love to see your two loop solution. I appreciated your advice and your dedication to making that scenario work. It amazes me that there are so many ways to solve the same problem with JavaScript, and programming languages in general.


#12

Sorry for such a late reply, I have been very busy the last week or so I haven’t been able to work on this stuff much. Here is my two for loop solution that passes all the tests.

[spoiler]function titleCase(str){
var stringArray = str.toLowerCase().split(’ ');
var wordArray = [];
var finalArray = [];

for (i = 0; i < stringArray.length; i++){
wordArray.push(stringArray[i].split(’’));
}

for (j = 0; j < wordArray.length; j++){
var toCap = wordArray[j][0].toUpperCase();
wordArray[j].shift();
wordArray[j].unshift(toCap);
finalArray.push(wordArray[j].join(’’));
}

return (finalArray.join(’ '));
}
titleCase(“This iS a tESt seNTenCe”);[/spoiler]


#13

Awesome! Thanks for posting, @the702guy.


#14

Hi @janusoo,
I was playing with your solution & you don’t even need to create the empty array (line 3). See below.
Thx!

function titleCase(str) {
var wordsArray = str.toLowerCase().split(" ");

// var charsArray = [];

for (i = 0; i < wordsArray.length; i++) {
charsArray = wordsArray[i].split("");
charsArray[0] = charsArray[0].toUpperCase();
wordsArray[i] = charsArray.join("");
}

str = wordsArray.join(" ");
return str;

}

titleCase(“I’m a little tea pot”);