Title Case a Sentence. Is there any chance for this code to work?

Title Case a Sentence. Is there any chance for this code to work?
0

#1

There are enough comments in the code below.
The right letter gets capitalized, but the replacement goes wrong.

  function titleCase(str) {

      // make all leters toLowerCase and convert str to array
      let arr = str.toLowerCase().split(' ');
      let arr1 = [];

      for (var i = 0; i < arr.length; i++) {

        // take the first letter of every element and turn it to upperCase
        let replace = arr[i].charAt(0).toUpperCase();
        console.log('replace ', replace);

        // This log shows that the right letter gets capitalized
        // but it gets assigned at the begining of the array
        console.log(arr);

        // delete the first letter of every element and replace it...
        arr1 = arr.splice(arr[i].charAt(0), 1, replace);

        // the replacement did not succeed
        console.log('charAt(0) ', arr[i].charAt(0));
      }

      return arr1.join(' ')
    }
titleCase("I'm a little tea pot");

Your browser information:

User Agent is: Chrome.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-algorithm-scripting/title-case-a-sentence/


#2
arr1 = arr.splice(arr[i].charAt(0), 1, replace);

You need to review what the splice method returns. You apparently think it returns a new version of arr after the splice takes place, but you it is not. Plus, the first argument should be an index value and not a string character. The code below is a string and not an index (integer starting at 0).

arr[i].charAt(0)

#3

Thanks for your help.
Now I don’t assign the modified array to an other one.
Plus I give an index value to the first argument with indexOf().
But still nothing.
I did some other tests with splice method, and it seems that when it’s in a for loop,
it cuts off the array at the first occurrence.
So this:

var myFish = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon'];

    myFish.splice(3, 1);

console.log(myFish); // ["angel", "clown", "drum", "sturgeon"]

But this:

  var myFish = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon'];

    for (var i = 0; i < myFish.length; i++) {
      myFish.splice(3, 1);
    }
    console.log(myFish); //  ["angel", "clown", "drum"] there's no "sturgeon"

So, I don’t see a way for it to work
Or is there?

Below’s the modified code

function titleCase(str) {

     // make all leters toLowerCase and convert str to array
     let arr = str.toLowerCase().split(' ');


     for (var i = 0; i < arr.length; i++) {

       // take the first letter of every element and turn it to upperCase
       let replace = arr[i].charAt(0).toUpperCase();
       console.log('replace ', replace);

       // This log shows that the right letter gets capitalized
       // but it gets assigned at the begining of the array
       console.log(arr);

       // delete the first letter of every element and replace it...
       arr.splice(arr[i].indexOf(arr[i].charAt(0)), 1, replace);

       console.log('first letter ', arr[i].charAt(0));
       console.log('index of first letter ', arr[i].indexOf(arr[i].charAt(0)));
       // the replacement did not succeed
       console.log('charAt(0) ', arr[i].charAt(0));
     }

     return arr.join(' ')
   }
   console.log('result: ', titleCase("I'm a little tea pot"));

#4

arr[i].indexOf(arr[i].charAt(0)) will always evaluate to 0, because arr[i].charAt(0) is the first character of arr[i] and indexOf is going to return the first index it finds matching the value specified as it’s argument. In this case, it will be the first index (0).

You are overthinking this a bit. arr[i] contains each word. All you want to do is replace arr[i] with an uppercase character of the first letter and the rest of arr[i] will be lowercase.

You need to break arr[i] into two pieces:

  1. first element of arr[i]
  2. the rest of arr[i] after first element.

The first one is very easy if you think about it. The second one could involve using slice (not splice).

Finally, you can reassign arr[i] the concatenation of the uppercase of the 1st part and the lowercase of the 2nd part described above.


#5

Man thanks so much !!!
I have a piece of code that finally works. But…
I just used the replace method, when I was trying

" replace arr[i] with an uppercase character of the first letter and the rest of arr[i] will be lowercase "

as you asked me to do.
Then I realized the code would pass the challenge.

But, I couldn’t leave it there, because you suggested that there is a way with splice.
So I went on trying to use the slice method.
I created two arrays,

  1. with the first letter capitalized
  2. with the rest of word

But I have a problem with concatenating the two arrays.
There is a space between concatenated elements

Spoiler
    // This one works, but I use the replace method, not slice.
        function titleCase(str) {

          // make all leters toLowerCase and convert str to array
          let arr = str.toLowerCase().split(' ');
          let arr1 = []

          for (var i = 0; i < arr.length; i++) {


            console.log('each word ', arr[i]);
            console.log('first letter ', arr[i].charAt(0));
            console.log('first letter capitalized ', arr[i].charAt(0).toUpperCase());

            // On each word replace the first letter with a capitalized one.
            arr1.push(arr[i].replace(arr[i].charAt(0), arr[i].charAt(0).toUpperCase()));


            console.log(arr1);

          }

          return arr1.join(' ');
        }
        console.log('result: ', titleCase("I'm a little tea pot"));
      ```

The next one is with slice

    // This one is with slice
      function titleCase(str) {

      // make all leters toLowerCase and convert str to array
      let arr = str.toLowerCase().split(' ');

      // Why this doesn't work?
      // let arr1, arr2, arr3 = [];

      let arr1 = [];
      let arr2 = [];
      let arr3 = [];
      console.log(arr1);
      console.log(arr2);

      for (let i = 0; i < arr.length; i++) {
        // capitalize first letter and push it to arr1
        arr1.push(arr[i].charAt(0).toUpperCase())
        //console.log(arr[i].charAt(0).toUpperCase());

        // slice the rest of the arr[i] word
        arr2.push(arr[i].slice(1, ))
        //console.log(arr2);
      }
      // concat the two arrays
      function concatArr(arr0, arr1) {
        let arr2 = [];

        for (let i = 0; i < arr0.length; i++) {
          for (let j = 0; j < arr1.length; j++) {
            arr2.push(arr0[i]);
            arr2.push(arr1[i])
            break;
          }
        }
        return arr2.join(' ');
      }
      return concatArr(arr1, arr2);
    }

    console.log('result: ', titleCase("I'm a little tea pot"));

result:  I 'm A  L ittle T ea P ot

#6

Again, in your second example, you are making this more complicated than it needs to be.

When I said break it into two pieces, you could have just used two string variables like the following inside your first for loop.

var firstLetter = arr[i][0]; // references the first letter of each word (arr[i])
var restOfWord = arr[i].slice(1); // rest of the word (arr[i])

With the above, you can simply use the toUpperCase and toLowerCase methods on the applicable variable when concatenating the two strings together. Then, you would just reassign the current value of arr[i] to this concatenated value. If you do not want to mutate the original arr, then you would use only one extra array which you would set to empty before the for loop and then push the concatenated string to the other array inside the for loop.


#7

Bingo!
I have no words to thank you.

spoiler

   // this one is with slice
    function titleCase(str) {

      // make all leters toLowerCase and convert str to array
      let words = str.toLowerCase().split(' ');

      let titleCasedWords = []
      for (let i = 0; i < words.length; i++) {

        var firstLetter = words[i][0].toUpperCase();
        //console.log(firstLetter);

        // slice the rest of the words[i] word
        var restOfWord = words[i].slice(1);
        //console.log(restOfWord);

        titleCasedWords.push(firstLetter += restOfWord);
        //console.log('FL ', firstLetter);

      }

      // concat the two arrays
      return titleCasedWords.join(' ');

    }

    console.log('result: ', titleCase("sHoRt AnD sToUtt"));
// result:  Short And Stoutt

I’m on the repetition now, and I came up with a better way maybe.

    function titleCase(str) {

      let str1 = str.toLowerCase();
      let words = str1.split(" ");
      let titleCasedWords = [];

      for (var i = 0; i < words.length; i++) {
        titleCasedWords.push(words[i][0].toUpperCase() + words[i].slice(1));
      }
      return titleCasedWords.join(" ");
    }

    console.log('result', titleCase("sHoRt AnD sToUt"));

#8

To make your solution more readable, try naming your arr and arr2 variables to describe what they contain. For example, arr could be changed to words and arr2 changed to titleCasedWords.

This function is short so it is easy to understand without these naming conventions, but imagine if the function was 100 lines of code. By making each variable name describe the data contained, someone does not have to scroll all the way back to the point where the variable is declared or updated to figure out what data it might contain.


#9

Thanks for the tip. I made the changes and I’ll be more semantic from now on.