loading...

Capitalize the first letter of every word

318097 profile image Mehul Lakhanpal ・1 min read

Alt Text

Thanks for reading 💙

Follow @codedrops.tech for daily posts.

InstagramFacebook

Micro Learning ● Web Development ● Javascript ● MERN stack

www.codedrops.tech

Discussion

pic
Editor guide
Collapse
aminnairi profile image
Amin

Hi there, very nice use of the String & Array prototypes chains. Thanks for your solution.

If I may, I would like to suggest another alternative involving less time complexity and using a sentinel value for detecting spaces. Because using split and map and join means many loops through the strings and array items generated.

The following algorithm can reduce the time complexity to O(n), n being the number of characters in the text.

"use strict";

const capitalize = (text) => {
    let isPreviousLetterSpace = true;
    let capitalized = "";

    for (const letter of text) {
        if (isPreviousLetterSpace) {
            isPreviousLetterSpace = false;
            capitalized += letter.toUpperCase();
            continue;
        }

        if (letter === " ") {
            isPreviousLetterSpace = true;
            capitalized += letter;
            continue;
        }

        capitalized += letter.toLowerCase();
    }

    return capitalized;
};

const text = "hello world";
const capitalized = capitalize(text);

console.log(capitalized); // "Hello World"

I also run some performance tests to see the outcome and it seems like the solution you provided is around 40 to 50% slower than the one I provided. So performance in the case of capitalizing hundreds or thousands of strings should be taken into account I guess. It was tested on Google Chrome and may vary from a browser to another.

What do you think about it?

Just for the record: I'm not saying that your solution is wrong. In the contrary, I think that solution you provided is the best because it involves less complexity to find the perfect algorithm to solve the task and premature optimizations like I just did should never happen unless you have a very good reason to. What I showed is only for finding an alternative solution and discuss about it.

Also, you made a very minor typo by writing capitlize instead of capitalize for the name of the function. But that's okay.

Again, very good work mate!

Collapse
euantorano profile image
Euan T

Another alternative would be using a regular expression, which is quite nice and compact:

function capitalize(text) {
  return text.replace(/(^[a-z]| [a-z])/g, function (match, letter) {    
    return letter.toUpperCase();
  });
}

const text = "hello world";
const capitalized = capitalize(text);

console.log(capitalized); // "Hello World"

This also turns out to be even faster in my benchmarks - this will be due to the regular expression engine being highly optimised and built into the browser. My results from the perf.link site (which doesn't seem to want to let me copy a link directly to the benchmark for some reason...) are as follows:

function ops/s %
regexCapitalize 446,440 100%
capitalize2 184,960 41%
capitalize 144,600 32%
Collapse
318097 profile image
Mehul Lakhanpal Author

That's awesome. Hell lot of difference🔥

Collapse
anders profile image
Anders

This looks like a better version from a performance perspective for sure, I did this implementation of the same

function captilizeAllWords(s) {

  var capitalize = true;
  var returnValue = '';

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

    var c = s[i];

    if (c == ' ') { 

      capitalize = true; 

    } else if (capitalize) {

      c = c.toUpperCase();
      capitalize = false;
    }

    returnValue += c;
  }

  return returnValue;
}

In an article I wrote here a few days ago: dev.to/anders/why-do-we-write-java...

Given that "of" seems like it may be a little slow this is probably even faster.

Collapse
lukaszahradnik profile image
Lukáš Zahradník

Your algorithm will not reduce the complexity to O(n), because the algorithm in the article already has time complexity O(n)

Collapse
alexanderjanke profile image
Alex Janke

Just on my phone right now but "split map join" in your perf-url is constantly 20-40% faster than the for loop version. I've done like 20 iterations now and number 2 is always faster (at least for me)

Collapse
318097 profile image
Mehul Lakhanpal Author

Lol. I made 2 typos actually. Got to know it now 😂😂 thanks though..👍😀

Collapse
318097 profile image
Mehul Lakhanpal Author

Sure, there are tradeoffs with every solution.

Collapse
willsmart profile image
willsmart

Case conversion can get a bit tricky with edge cases, like does "one.two" have one word or two, and what of words separated by tabs or newlines.
Often using a regular expression is the way to go.

Can I suggest something like this code, based on a small regex...

toTitleCase = sentence => sentence.replace(
  /\b[a-z]/g, 
  firstCharOfWord => firstCharOfWord.toUpperCase()
)

Regular expressions have a builtin assertion \b which can be used to detect word boundaries. The regex /\b[a-z]/ will match wherever the first letter of any word is lowercase. i.e. wherever a word boundary (i.e. not a letter, number or underscore) is followed by a lowercase letter.

String.replace takes a function that cleanly provides uppercased replacements for the matching letters.
I'm guessing this will be faster, though I haven't done benchmarking. It certainly does fewer calls to toUpperCase

Collapse
alexanderjanke profile image
Alex Janke

I added your function to the benchmark site linked by @aminnairi
Benchmark hello world

Regex seems to performance the fastest... mostly. I'm not really sure how that site samples it's benchmark but it seems awfully fast, meaning few iterations? Having done roughly 30 iterations by hand your regex seems to be ~5-10% faster than the split-map-join. Sometimes the split-map-join is faster though, by a small margin. This is for "hello world" though. Once you start to use longer sentences, your regex becomes the clear winner by a huge margin (roughly 30-40% faster).
Benchmark with longer sentence

Collapse
willsmart profile image
willsmart

Hey thanks for that, that's awesome!

One nice thing about the regex way is that it targets the letters it needs to capitalize. I added test cases for an already capitalized sentence and toTitleCase gets a 400% speedup compared to the non-capitalized sentence (since it won't call toUpperCase if it doesn't need to). The others didn't get any speed up (their code could be tweaked, but I don't think there's a way to get such a boost).
Benchmark here

Collapse
318097 profile image
Mehul Lakhanpal Author

I really liked this solution. Thanks for writing it.

Collapse
willsmart profile image
willsmart

Thanks Mehul