DEV Community

loading...

Daily Challenge #3 - Vowel Counter

thepracticaldev profile image dev.to staff ・1 min read

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!

Discussion (86)

pic
Editor guide
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
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
taillogs profile image
Ryland G

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

Collapse
torianne02 profile image
Victoria 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
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);
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
protium profile image
Brian Mayo

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
aspittel profile image
Ali Spittel

My python solution!

def count_vowels(word):
    return len(l for l in word if l in "aeiou")
Enter fullscreen mode Exit fullscreen mode
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
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
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
shayaulman profile image
Shaya Ulman • Edited

Why not so simple as this (JS)...

const vowelsCounter = str => [...str].filter(l => 'aeiouAEIOU'.includes(l)).length;
Collapse
willsmart profile image
willsmart • Edited

JS one that's probably pretty speedy

vowelCount = string => {
  let count = 0,
    i;
  for (i = string.length; i > 0; ) {
    const c = string.charCodeAt(--i) & ~0x20; // that's a tilde btw
    count+=Number(c < 70 ? c == 69 || c == 65 : c == 73 || c == 79 || c == 85)
  }
  return count;
};

Note that:

{E:'E'.charCodeAt(0), A:'A'.charCodeAt(0), I:'I'.charCodeAt(0), O:'O'.charCodeAt(0), U:'U'.charCodeAt(0)}

-> {E:69, A:65, I:73, O:79, U:85}

and vowels go pretty much eaiou in terms of how common they are in english.

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
robbitt07 profile image
robbitt07

Python regex example

import re
def num_vowels(s):
    return len(re.findall('[aeiou]', s))
Collapse
kesprit profile image
kesprit

This is my solution in Swift (with an extension 😊) :

extension String {
    func numberOfVowels() -> Int {
        var count = 0
        let vowels: [Character] = ["a","e","i","o", "u", "y"]

        self.lowercased().forEach { char in
            if vowels.contains(char) {
                count += 1
            }
        }

        return count
    }
}
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
bennypowers profile image
Benny Powers 🇮🇱🇨🇦 • Edited
module Vowels (countVowels) where

import Data.Char (toUpper)

isVowel :: Char -> Bool
isVowel = flip elem "AEIOU"

countChar :: Char -> Integer
countChar letter = if isVowel letter 1 else 0

countVowels :: String -> Integer
countVowels = sum . map (countChar . toUpper)

Will have to double check the syntax (on Mobile) but I think this will work

Collapse
mwlang profile image
Michael Lang

Ruby Language

with specs

def vowels str
  str.to_s.scan(/[aeiou]/i).size
end

require "spec"

describe "#vowels" do
  it { expect(vowels nil).to eq 0}
  it { "aeiou".split('').each{|v| expect(vowels v).to eq 1} }
  it { "AEIOU".split('').each{|v| expect(vowels v).to eq 1} }
  it { expect(vowels "foo").to eq 2}
  it { expect(vowels "FOO").to eq 2}
  it { expect(vowels "BCDFG").to eq 0}
  it { expect(vowels "QuEUeInG").to eq 5}
end

output

>> rspec vowels.rb
.......

Finished in 0.00579 seconds (files took 0.14931 seconds to load)
7 examples, 0 failures
Collapse
pmkroeker profile image
Peter • Edited

In go!

func countVowels(s string) int {
    l := strings.ToLower(s)
    count := 0
    for _, c := range l {
        switch c {
        case 'a':
            fallthrough
        case 'e':
            fallthrough
        case 'i':
            fallthrough
        case 'o':
            fallthrough
        case 'u':
            count++
        }
    }
    return count
}

Go playground example

Uses fallthrough mostly because I wanted to, count++ would be smaller, but all cases behave the same (also its more easily maintainable).

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
centanomics profile image
Cent

My solution is a bit longer because I don't know regex, but it gets the job done.

CodePen


const countVowels = text => {
  let count = 0;
  text.toLowerCase().split("").forEach(char => {
    if (char === "a" || char === "e" || char === "i" || char === "o" || char === "u")
      count++;
  })
  return count;
}

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
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)
Collapse
necrotechno profile image
NecroTechno
use regex::Regex;

fn main() {
    let re = Regex::new(r"[aeiou]").unwrap();
    let mut result: i32 = 0;
    for _mat in re.find_iter("Hello, world!") {
        result += 1;
    }
    println!("Vowel count: {:?}", result)
}

Link to playground - play.rust-lang.org/?version=stable...

Collapse
ryanwilldev profile image
Ryan Will • Edited

A solution in Elixir

defmodule VowelCounter do
  @vowels ~r/(a|e|i|o|u)/i
  
  def count(""), do: 0

  def count(string) do
    @vowels 
    |> Regex.scan(string)
    |> Enum.count() 
  end
end
Collapse
margo1993 profile image
margo1993 • Edited

GO

func FindVowelsCount(sentence string) int {
    vowels := []string{"a", "e", "i", "o", "u"}
    lowerCaseSentence := strings.ToLower(sentence)

    vowelsCount := 0
    for _, c := range lowerCaseSentence {
        if contains(vowels, string(c)) {
            vowelsCount++
        }
    }

    return vowelsCount
}

func contains(list []string, item string) bool {
    for _, w := range list {
        if w == item {
            return true
        }
    }
    return false
}
Collapse
calebefazzani profile image
calebefazzani • Edited

Ruby:

def removeAccents(str)
    accents = {
        ['á','à','â','ä','ã'] => 'a',
        ['é','è','ê','ë'] => 'e',
        ['í','ì','î','ï'] => 'i',
        ['ó','ò','ô','ö','õ'] => 'o',
        ['ú','ù','û','ü'] => 'u'
      }
      accents.each do |ac,rep|
        ac.each do |s|
          str = str.gsub(s, rep)
        end
      end
      str = str.gsub(/[^a-zA-Z0-9\. ]/,"")
      str = str.gsub(/[ ]+/," ")
  str = str.gsub(/ /,"-")
  return str
end


def verifyVowels(texto)
    allLc = removeAccents(texto.downcase);
    countVowels = 0;
    allLc.split("").each do |letra|
        if (letra == 'a') | (letra == 'e') | (letra == 'i') | (letra == 'o') | (letra == 'u')
            countVowels+= 1;
        end
    end
    return countVowels
end
Collapse
moreginger profile image
moreginger

Haxe

static function vowels(s:String):Int {
  var vowels = 0;
  for (i in 0...s.length) {
    switch (s.charAt(i)) {
      case 'a' | 'A' | 'e' | 'E' | 'i' | 'I' | 'o' | 'O' | 'u' | 'U':
        vowels++;
    }
  }
  return vowels;
}

iterators library looked useful but you can't fold an iterator, only an iterable, disappoint.

Collapse
jasman7799 profile image
Jarod Smith
function countVowels(string) {
  if(typeof(string) !== 'string')
    throw new Error('input must be a string');

  const vowels = 'aeiouAEIOU';
  let vowelCount = 0;

  for(index in string) {
    if(vowels.includes(string.charAt(index)))
      vowelCount++;
  }
  return vowelCount;
}

ledgible I hope

Collapse
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

Could also

const compose = (...fns) => fns.reduce((f, g) => (...args) => (f(g(...args)));
Collapse
wolverineks profile image
Kevin Sullivan
const isIncludedIn = <Data>(collection: Data[]) => (value: Data) =>
  collection.includes(value);
const toChars = (input: string) => [...input];
const length = (xs: any[]) => xs.length;
const keepIf = filter => (xs: any[]) => xs.filter(filter);
const pipe = (...fns: Function[]) =>
  fns.reduce((f, g) => (...args) => g(f(...args)));

const detect = (detectableChars: string[]) =>
  pipe(
    toChars,
    keepIf(isIncludedIn(detectableChars)),
    length,
  );

const VOWELS = {
  LOWERCASE: ["a", "e", "i", "o", "u"],
  UPPERCASE: ["A", "E", "I", "O", "U"],
};
const DETECTABLE_LETTERS = [...VOWELS.LOWERCASE, ...VOWELS.UPPERCASE];
export const vowelCounter = detect(DETECTABLE_LETTERS);

Collapse
chukkyiii profile image
Jesse Godwin • Edited

Python

def vowelcounter(string):
    i = 0
    string = string.lower()

    for x in string:
        if x in 'aeiou':
            i += 1
    print(i)

vowelcounter("This is a test")