DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #3 - Vowel Counter

Hope you’re ready for another challenge! Let’s get started with Day 3.

Today’s challenge is modified from user @jayeshcp on CodeWars.

Write a function that returns the number (count) of vowels in a given string. Letters considered as vowels are: a, i, e, o, and u. The function should be able to take all types of characters as input, including lower case letters, upper case letters, symbols, and numbers.

In this challenge, you should be able to efficiently ignore spaces and symbols and discern between capital and lowercase letters. Beginners can start with only lowercase letters and move up from there. It’ll definitely get you ready for tomorrow.

Happy coding!~


Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge for a future post? Email yo+challenge@dev.to with your suggestions!

Oldest comments (82)

Collapse
 
taillogs profile image
Ryland G • Edited
const vowelString = 'whatever vowel string';
const count = [...(vowelString.toLowerCase())].map((letter) =>  [...'aeiou'].includes(letter) ? 1 : 0).reduce((aggr, curr) => aggr + curr);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
powerc9000 profile image
Clay Murray

[...'aeiou'].includes

Collapse
 
taillogs profile image
Ryland G

Fixed, thanks!

Collapse
 
gabriela profile image
Gabi

Hi, i loved this solution. Took me a bit to get my head around the use of reduce here and it's awesome. Thanks. I learned something nice today.

Collapse
 
blended_ideas profile image
Karthik RP • Edited

Cool., I didn't know we can use spread on a string. 👍🏻

Collapse
 
coreyja profile image
Corey Alexander

Oh I've been waiting for this one all morning! Decided I wanted to go all out on this on!

  • Rust
  • TDD
  • AND a Live Stream!

Come check it out while I work my way through this challenge! I'm live now and about to get started!

twitch.tv/coreyja

Collapse
 
coreyja profile image
Corey Alexander

Here is my Rust solution all TDD'ed out!

#[macro_use]
extern crate lazy_static;

pub fn vowel_count(some_string: &str) -> usize {
    lazy_static! {
        static ref VOWELS: Vec<char> = vec!['a', 'e', 'i', 'o', 'u'];
    }

    some_string
        .to_ascii_lowercase()
        .chars()
        .filter(|c| VOWELS.contains(c))
        .count()
}

#[cfg(test)]
mod tests {
    use crate::vowel_count;

    #[test]
    fn it_works_with_an_empty_string() {
        assert_eq!(vowel_count(""), 0);
    }

    #[test]
    fn it_works_non_vowel_strings() {
        assert_eq!(vowel_count("d"), 0);
        assert_eq!(vowel_count("drthpCVM  *&^"), 0);
        assert_eq!(vowel_count("1234567890!@#$%^&*()--__+="), 0);
        assert_eq!(vowel_count("NPlkv.,<>?/"), 0);
    }

    #[test]
    fn it_works_for_strings_of_just_vowels() {
        assert_eq!(vowel_count("a"), 1);
        assert_eq!(vowel_count("A"), 1);
        assert_eq!(vowel_count("AaeEiIoOuU"), 10);
        assert_eq!(vowel_count("eoiuioEAUIAEoieaiAoe"), 20);
    }

    #[test]
    fn it_works_for_mixed_strings() {
        assert_eq!(vowel_count("deadpool"), 4);
        assert_eq!(
            vowel_count("This is just a sentence! With some words and symbols #$%"),
            13
        );
        assert_eq!(vowel_count("TESTING OUT YELLING WITH ALL CAPS"), 9);
        assert_eq!(
            vowel_count("!@#      \nThis is THE MOST COMPLICATED test SoO farrrr"),
            12
        );
    }
}

I'm still live streaming as I type this out, but once I wrap up I'll post a link to the video here!

Collapse
 
coreyja profile image
Corey Alexander • Edited

Ahhh! :panic:

Turns out OBS didn't want to behave for me today, and split my stream into 2 and dies before I finished, but we got almost all of it recorded! Learnings for next stream!

Links to the video that recorded for the longest here

Collapse
 
alvaromontoro profile image
Alvaro Montoro • Edited

JavaScript:

f=s=>s.match(/[aeiou]/gi).length
Enter fullscreen mode Exit fullscreen mode

Demo on CodePen.

Collapse
 
taillogs profile image
Ryland G

I think this is the best solution if you're ok with regex.

Collapse
 
ryansmith profile image
Ryan Smith • Edited

Nice solution, mine was similar in using regex match, but not as short. This one will error on a string without any vowels because match will return a null which doesn't have a length.

Collapse
 
alvaromontoro profile image
Alvaro Montoro • Edited

That's a good point. This could be avoided by checking if the result of the match is null and using an empty string instead. Something like this:

f=s=>(`${s}`.match(/[aeiou]/gi)||'').length;

I also used template literals before the match so numeric values or null would be process too... and now the code is even uglier than before :P

Thread Thread
 
kvharish profile image
K.V.Harish

Typo ${s}

f=s=>(`${s}`.match(/[aeiou]/gi)||'').length;
Thread Thread
 
alvaromontoro profile image
Alvaro Montoro • Edited

Good catch! I corrected it. Thank you for letting me know!

Collapse
 
protium profile image
protium

Thinking the string as a Set with O(1) for look up operations: solution is O(n), where n = len(str)

def count_vowels(str):
    vowels = "aeiouAEIOU"
    count = 0
    for c in str:
        if c in vowels:
            count += 1
    return count;

JS lambda way

conat vowels = new Set("aeiouAEIOU");
const counVowels = input => [...input].reduce((total, current) => (total += vowels.has(current)), 0);
Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦
import { compose } from 'crocks';

const toLowerCase = s => s.toLowerCase();
const spread = s => [...s];
const length = xs => xs.length;
const included = xs => x => xs.includes(x);
const filter = p => xs => xs.filter(p);

const charIncludesCount = chars => compose(
  length,
  filter(included(toLowerCase(chars)),
  spread,
  toLowerCase
);

const vowelCount = charIncludesCount ('aeiou');
Collapse
 
ryansmith profile image
Ryan Smith • Edited

Here is my try at it in JavaScript:

/**
 * Count the number of vowels in the input and return an integer.
 */
function countVowels (inputText) {
  // Create a regular expression that matches vowels. Look for all matches (g flag) and ignore case (i flag).
  const vowelRegularExpression = /[aeiou]/gi

  // Convert the input text to lower case and find the matches.
  const vowelMatches = inputText.match(vowelRegularExpression)

  // If there are matches, return the length of the match array. Otherwise, there were no matches, so return 0.
  return (vowelMatches ? vowelMatches.length : 0)
}
Collapse
 
kerrishotts profile image
Kerri Shotts
const charCounter = ({strToCount = "", chars = ""} = {}) => {
    const charsToCount = chars.toLowerCase();
    return Array.from(strToCount.toLowerCase())
        .reduce((acc, candidate) => acc += charsToCount.includes(candidate) 
        ? 1 : 0, 0)
}

const countVowels= strToCount => charCounter({strToCount, chars: "aeiou"});

assert(countVowels("The quick brown fox jumps over the lazy dog.") === 11);
assert(countVowels("Hello") === 2);
assert(countVowels("Xyl") === 0);
assert(countVowels("aeiouAEIOU") === 10);
Collapse
 
torianne02 profile image
Tori Crawford • Edited

Ruby

Long Solution (my first solution)

def getVowelCount(str)
  vowels = ["a", "e", "i", "o", "u"]
  count = 0
  str.downcase.split('').each do |char|
    vowels.each do |vowel|
      char == vowel ? count += 1 : count += 0
    end
  end 
  count
end

Short Solution (my refactored solution)

def getVowelCount(str)
  str.downcase.count("aeiou")
end
Collapse
 
databasesponge profile image
MetaDave 🇪🇺

It would be interesting to know if str.count("aeiouAEIOU") was faster, or if reordering the letters to try to get the most likely match first was better – e.g. str.count("eiaouEIAOU")

Collapse
 
protium profile image
protium

Not sure if I follow. O(n log n) is worst than O(n). Insertions in a binary tree are expensive to keep it balanced.
If you use a set or hashmap assuming zero collisions, the look up is O(1). Then the bottke neck is in the string iteration. Right?

Collapse
 
auroratide profile image
Timothy Foster • Edited

TI-Basic Calculator, where the string is in Ans:

sum(seq(0<inString("AEIOUaeiou",sub(Ans,I,1)),I,1,length(Ans

And yes you can omit ending parens, which helps saves some bytes (:

Collapse
 
johncip profile image
jmc • Edited

We don't care about the vowels being ordered for this problem, so you'd be paying extra time (vs. a hash-based set, or just hard-coded equality checks) for a property you're not using.

Collapse
 
johncip profile image
jmc • Edited

Clojure:

;; with regex
(defn vowels [s]
  (count (re-seq #"(?i)[aeiou]" s)))
;; without
(defn vowels [s]
  (count (filter #(some #{%} "AaEeIiOoUu") s)))
 
johncip profile image
jmc • Edited

You also have to traverse the tree to get to the next letter. But I see what you mean. Only counting equality checks, hard-coding behaves like a linear search. My bad.

I think you might still be missing Brian's point that a hash set has O(1) lookup time, which is faster than the tree set's O(log n).

(On paper. Real-world implementations vary. e.g. Ruby's hashes just do linear search at this size.)

Collapse
 
jckuhl profile image
Jonathan Kuhl • Edited

JavaScript, using reduce:

function countVowels(string) {
    const vowels = 'aeiouAEIOU';
    return string.split('').reduce((counter, current) => {
        if(vowels.indexOf(current) != -1) {
            if(counter[current]) {
                counter[current] += 1;
            } else {
                counter[current] = 1;
            }
        }
        return counter;
    }, {});
}

console.log(countVowels('How much wood would a woodchuck chuck if a woodchuck could chuck wood?'));

// { o: 11, u: 7, a: 2, i: 1 }
Collapse
 
ganderzz profile image
Dylan Paulus • Edited

Nim

from unicode import toLower

proc countVowels(input: string): int =
  for i in toLower(input):
    if i in "aeiou":
      result += 1

if isMainModule:
  const input = "@PPLes!43"

  echo countVowels(input)