The Ultimate Guide to JavaScript Algorithms

Counting the Vowels in a String of Text

In this challenge, we will be working with strings and arrays. Strings and arrays are very much alike in that they are both collections of elements usually of the same type.

In order to manipulate arrays and strings to various outcomes we will make use of various methods built into JavaScript for such computations. Methods are simply actions or procedures that can be carried out on a thing by virtue of its type. For cars, this could be driving, for athletes, this could be running. And for arrays and strings?

We’d find out shortly!

You should already have your development environment setup for this course. Open the cloned repository and inside the Beginner folder, navigate to the vowelsCounter folder. Our work for this challenge will be done in here. Make sure to follow along in the index-START.js file.

The Challenge

Given a string of text containing 0 or more vowels, count the number of vowels that can be found within the text. For example:

vowelsCounter('anehizxcv') // will return 3

Algorithmic Thinking

Reading through the challenge statement above, you'd notice the phrase "given a string of text". From previous experience, this should bring the idea of functions to mind.

Functions are simply named sections of code that perform a specific task. They may accept values as parameters used for internal computation. When called, the values passed into them at the time are known as arguments.

We can breakdown the solution to this challenge in three steps generally:

  • We write a function that’d receive a parameter called text. It would be a string of any length which would be passed to the function as an argument when it is called.
  • Next, within the function we have to go through the text and search for occurrences of the English vowels (a,e,i,o,u).
  • The function then returns the total number of matches(vowels) found. This brings return statements to mind as they simply stop the execution of a function and return a value from that function.

    Code Implementation

We’ve got the boring stuff out of the way. Let’s get our hands dirty, shall we? We’d follow two approaches to solving this problem:

In this approach, we loop through each letter of the string passed and then check to see if they match any of the English vowels. Before running through the text we create a counter initialized to a value of zero. When a match is found, the counter is incremented. At the end of it all, we return the counter which represents the total number of vowels found.

Pretty simple right? Well here's our implementation:

/*
 An iterative approach to counting the number of vowels in a string of text.
 */

const Vowels = ["a", "e", "i", "o", "u"]

function vowelsCounter(text) {
    // Initialize counter
    let counter = 0;

    // Loop through text to test if each character is a vowel
    for (let letter of text.toLowerCase()) {
        if (vowels.includes(letter)) {
            counter++
        }
    }

    // Return number of vowels
    return counter
}

Well, that was pretty self explanatory, wasn’t it? Let's do a quick walk-through.

Solution Breakdown

  • First, we declared a constant "Vowels" which contained an array of the five English vowels.
  • Next, we make use of a for…of loop to iterate through each letter of the text. If you're not conversant with this, a for…of loop basically creates a loop iterating over iterable objects. Iterable objects could be strings, arrays, maps, sets etc. You can learn more here.
  • Notice how we convert all letters of the text to lowercase within the loop. This is because, we don't want to miss the instances of uppercase vowels within the passed text .
  • Next within the loop, we use an if statement to check if the selected letter is included in the array of vowels we defined earlier. Fittingly, we call the includes() method on the array of vowels to determine whether the array includes the selected letter, returning true or false as appropriate. Learn more about how includes() works here.
  • If the condition evaluates to true, we increment the counter.
  • After looping through we return the counter which is equivalent to the number of vowels found.

Yayyyyyy!!! We did good. Now let's consider a slightly more advanced yet concise approach.

Using Regular Expressions

Regular Expressions are quite a bit of trouble for most developers . Usually, we don't get to understand the syntax and its application. Hence, we mostly get some snippets online when we need to make use of them.

Now let's try to change that a bit!

Basically regular expressions help us find patterns of characters/ character combinations within strings. Why is this relevant to us? With regular expressions, we can find the desired characters within the text passed.

By extension, regular expressions can help us to do way more remarkable things such us filtering through text, search and replace functionality, data validation etc. However, my favorite thing about regular expressions is the fact that the basics of its use is same in many languages.

Without further ado, let's examine the solution.

Here's our implementation:

/*
 Using Regular Expressions to count the number of vowels in a string of text.
 */

function vowelsCounter(text) {
    // Search text with Regex and store all matching instances 
    let matchingInstances = text.match(/[aeiou]/gi);

    // Check if matching instances exist then calculate length
    if (matchingInstances) {    
        // Return number of vowels
        return matchingInstances.length
    } else {
        return 0
    }
}

Solution Breakdown

  • The first thing we did within the function was to call the .match() method on the text. It returns an array of the matches found after comparing the regular expression passed in as an argument with the text. Learn more about how .match() works here.
  • The regular expression specifies the letters to be looked for within the brackets[]. For simple patterns, Regular expressions are usually defined within a pair of slashes. Notice the characters gi trailing the closing slash?
  • g stands for a global search which means that after finding the first match, it will not start over from the beginning but continue searching from the end of the previous match.
  • i stands for case insensitive search which makes the whole expression case-insensitive (for example /xyz/i would match XyZ).
  • Next we use a conditional to check if any matching instances were found. The .match() method used above returns an array of the matched items if matches were found and "null" if they weren't. Hence in the conditional, if matchingInstances evaluates to a truthy value(that is an array of matches found), we return the number of matches found which is also the length of the array. On the other hand if it evaluates to a falsy value, we return 0 as it means no matches were found.

Testing

It is now time for us to test our solutions with Jest and JsPerf. This will determine if our algorithms work under the specified conditions and help us know the most optimal solution.

Testing Correctness with Jest We test each algorithm by running the command below for each case:

npm run test vowelsCounter

Here are the results:

  • The Iterative Approach

  • Using Regular Expressions

Notice that in both cases we have passed all 5 tests. Good job!

The estimated time taken to run the tests for each algorithm isn’t a proper indication of the performance characteristics of each implementation.

Testing Performance with JSPerf I have created a comparison between both methods explored above here on JSPerf. Here’s the result:

Make sure to try it out on your own to ensure you have similar results. The result as shown above leads us to the conclusion that:

The Regex Method is approximately 88% faster than The Iterative Approach to solving this problem. Thus, it is a more optimal solution.

Practical Application

The challenge considered here is mostly encountered in JavaScript Interviews where you may be expected to carry out computations on a string of text.

Conclusion

From considering this challenge and trying to solve it in the ways highlighted above,we see clearly that the iterative approach although not as concise as when regex is used, is an easier and somewhat more intuitive approach especially for beginners. However as the result shows, the Regex method is better optimized.

Nevertheless, both implementations may pass in an interview depending on the objective.

Further Reading

To learn more about some of the concepts highlighted while solving this challenge, use the resources below:

Happy Coding! See you in the next one.

Like this article? Follow @worldclassdev on Twitter