Title Case Algorithm Challenge: Why is only one word of the array returned to console?

  1. When run through the console, the following code returns [“i”, “”, “m”] when inside of the for loop. When returned outside of the for loop, it returns [“p”, “o”, “t”]. Why is that?

  2. In both instances, why does it only return the letters of one word in the array? Since it’s being run through a for loop that is supposed to stop iterating at the end of the array’s length, shouldn’t it return every single word’s letters to the console? Instead of returning [“i”, “”, “m”], for example, shouldn’t it return [“i”, “”, “m”, " ", “a”, " ", “l”, “i”, “t” … ] to the console?

function titleCase(str) {
  
var strSplit = str.toLowerCase().split(' ');

  for(var i = 0; i < strSplit.length; i++) {
  var letters = strSplit[i].split('');
  return letters;
  }
     

}

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

This is a part of the code to the “Title Case” algorithm challenge. If curious, the whole code is as follows. I’m just trying to understand how each part of the code works, because I had a lot of trouble with it. I’ve added comments to show my basic understanding of the code (please correct me if I’m wrong), but I’m still confused about the two points above.

function titleCase(str) {
  
var strSplit = str.toLowerCase().split(' '); 
// splits into words 

  for(var i = 0; i < strSplit.length; i++) {
  var letters = strSplit[i].split(''); 
    /* splits each word into letters and becomes subarrays? ex: [["i", "", "m"], [" "], ["a"] ...] not sure if this is right */
    letters[0] = letters[0].toUpperCase(); 
    // takes first letter of each word in array aka subarray (?)
    strSplit[i] = letters.join('');
    // join split letters back together into words
  }
     
  return strSplit.join(' ');
  // joins all words together to form a string 
}

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

It’s because the first word in strSplit is "i'm". Splitting it further yields ["i", "'", "m"]. Then you hit the return statement. Returning from inside a loop effectively breaks it, so you end up with that array.

This time the for-loop has the chance to loop through every word in strSplit. Everytime, you’re reassigning the letters variable. The last value it will hold will be the split last word, so you get ['p', 'o', 't'].

Again, it’s because of the reassignment of the letters variable. Every time the loop runs, you’re slapping in a new array to that variable. If you want to achieve that array, you’ll have to tweak your code a bit. Here’s one way you could do it:

function titleCase(str) {
  
  var strSplit = str.toLowerCase().split(' ');
  var letters = [];
  
  for(var i = 0; i < strSplit.length; i++) {
    letters = letters.concat(strSplit[i].split(''));
  }
     
  return letters;
}

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

Why does it stop executing at the first array if the for loop says to execute until the end of it?

Splitting the words into letters creates a subarray of the words, correct? So instead of [“i’m”, “a”, “little”, “tea”, “pot”] it becomes [[“i”, “”, “m”], [" "], [“a”] …]]?

function titleCase(str) {
  
var strSplit = str.toLowerCase().split(' ');

  for(var i = 0; i < strSplit.length; i++) {
  var letters = strSplit[i].split('');
  return letters;
  }
     

}

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

There are ways to break out of a for-loop. return is one of them.

It’s useful if you think about it. Say you are using a for-loop to look for an item in an array. If you found what you’re looking for, you can then return out of it, since there’s no more point in continuing the loop.

If you split the string at spaces, the spaces won’t be part of the array. You’ll have instead

[["i", "'", "m"], ["a"], ["l", "i", ...], ...]

I’m having a lot of trouble understanding this :confused:

In the following code, why does running letters[1] instead of letters[0] not work?

function titleCase(str) {
  
var strSplit = str.toLowerCase().split(' '); 


  for(var i = 0; i < strSplit.length; i++) {
  var letters = strSplit[i].split(''); 
    letters[1] = letters[1].toUpperCase(); 
    strSplit[i] = letters.join('');
  }
     
  return strSplit.join(' ');
}

titleCase("I'm a little tea pot");
"I'm A Little Tea Pot"

And when it is set to 0, how does this line in the code letters[0] = letters[0].toUpperCase(); tell the computer to jump to the next subarray to change the case of the first letter? I’m having trouble imagining how each line of code looks. I know it might be a lot to ask, but do you think you could illustrate how each line looks when it’s executed?

The trouble arises when you have a one-letter word (like "a"), because then you’re trying to access its second character, but there’s none.

Before the for-loop runs, you have this array stored in strSplit:

[ "i'm", "a", "little", "tea", "pot" ]

Now you start the for-loop. First a variable called i is created and set to 0. Then the condition i < strSplit.length is checked. Since 0 is less then the number of items in strSplit (5 in all), the for-loop will proceed with running the code in the loop body.

Now we hit this line: var letters = strSplit[i].split('');

Here, strSplit[i] will evaluate to the first item in strSplit (we have i holding the value 0, as per its starting value. And array indexes are zero-based, so the first item is 0, the second is 1, and so on).

We then split it into its individual characters, so we have ["i", "'", "m"]. We now create a variable called letters and store this array there.

Now we hit this line: letters[0] = letters[0].toUpperCase();

Here we take the first item in the letters array (the letter "i") and make an uppercase version of it with .toUpperCase(). We then reassign the first letter with this uppercase "I". So now the letters array is ["I", "'", "m"].

Now we hit this line: strSplit[i] = letters.join('');

We’ll now join the letters array into one string. After joining, we have the string "I'm". We now reassign strSplit[i] with this new string (replacing its previous "i'm" value).

Now there’s no more lines in the loop body to execute. The strSplit array looks like this: [ "I'm", "a", "little", "tea", "pot" ].

At the end of the loop body, the i++ will run, incrementing the i variable from 0 to 1. After this the condition will be checked again. Since 1 is less than 5, the loop body will run again, doing the same steps as above, but this time, strSplit[i] will evaluate to the second item in strSplit (the one-letter word "a").

Here’s what strSplit looks like at each pass of the loop:

When i is 0, [ "I'm", "a", "little", "tea", "pot" ]
When i is 1, [ "I'm", "A", "little", "tea", "pot" ]
When i is 2, [ "I'm", "A", "Little", "tea", "pot" ]
When i is 3, [ "I'm", "A", "Little", "Tea", "pot" ]
When i is 4, [ "I'm", "A", "Little", "Tea", "Pot" ]

It will keep doing this until i increments from 4 to 5. Since 5 is not less than itself, we’ll now break out of the for-loop and run the return statement. It will join the contents of the strSplit array with spaces and return the string "I'm A Little Tea Pot"

Hello,

One thing I found very helpful when learning JS is the debugger.

This course: https://watchandcode.com/courses/enrolled/60264 (specifically the chapter labeled Interlude - Don’t wonder about things the debugger can tell you) gives a really awesome indepth explanation of how to use it. The course is free, and is also one of the first courses that made understanding what is going on in JavaScript make sense to me.

tl:dr console debugger is an awesome tool to step through the code line by line to see what it is doing.