Daily Challenge #3 - Vowel Counter

dev.to staff on June 30, 2019

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 ... [Read Full]
markdown guide
 
 

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.

 

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

Typo ${s}

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

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

 

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

 

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
 

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")

 
const vowelString = 'whatever vowel string';
const count = [...(vowelString.toLowerCase())].map((letter) =>  [...'aeiou'].includes(letter) ? 1 : 0).reduce((aggr, curr) => aggr + curr);
 
 

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.

 

My python solution!

def count_vowels(word):
    return len(l for l in word if l in "aeiou")
 

What if the word is in uppercase? Succinct though, my solution ended up like this:

import re

word = "sUpercalifragilisticexpialidocious"
def count_vowels(word):
    word = word.lower()
    letters = list(word)
    count = 0
    for letter in letters:
        if re.match("[aeiou]",letter):
            count += 1
    print count

count_vowels(word)

 

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);
 

The most efficient structure for this sort of lookup would be a binary tree, which has a O(log n) complexity for lookup, so such a solution would be O(n log n).

 

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?

I've made the assumption that the binary tree was already built, it could've been done during compile time, for instance.

As for hashing functions, you could get away with an Array where the index is the code point for a given character.

 

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.

I don't think so. Consider pseudocode like this:

if (letter == 'a' ||
    letter == 'e' ||
    letter == 'i' ||
    letter == 'o' ||
    letter == 'u') {
  vowels += 1;
}

Given the character 'u', it would do 5 comparisons, where the worst case for a binary tree would be 3. Cases where the letter isn't a vowel will involve 5 checks as well.

Edit: fixed the number of comparisons.

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.)

 

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

const vowelsCounter = str => [...str].filter(l => 'aeiouAEIOU'.includes(l)).length;
 

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)
}
 

I like to be explicit about types with these sorts of functions, and I assume Set is fast at looking up whether something belongs to it.

const vowels = new Set('aeiou');

const countVowels = (input) =>
      [...String(input).toLocaleLowerCase()].reduce(
        (count, character) => (vowels.has(character)
                               ? count + 1
                               : count),
        0);

console.log(countVowels('This is a TEST'));
 

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

 

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!

 

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

 
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');
 

You could replace the import of compose with a tiny implementation of it that looks like this (and could be shortened to one line if you really want to):

const identity = (x) => x;
const compose2 = (f, g) => (x) => f(g(x));
const compose = (...funcs) => funcs.reduce(compose2, identity);
 

Could also

const compose = (...fns) => fns.reduce((f, g) => (...args) => (f(g(...args)));
 

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 (:

 

Python regex example

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

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 }
 

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.

 
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

 

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).

 

SQL (Postgres)


\set x 'Hello world'

 select count(*) from                                                                                            
   (select 
     regexp_matches(:'x', '[aeiou]', 'gi')) 
     as vowels; 

 
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);

 
const test = require('./tester');
const vowelCount = str => String(str)
    .toLowerCase()
    .split('')
    .filter(ch => 'aeiou'.indexOf(ch) > -1)
    .length;

test(vowelCount, [
    {
        in: ["Hello O'Henry !"],
        out: 4,
    },
    {
        in: ['gnsp'],
        out: 0
    }
]);
 

Here's my solution:
PHP:


function countVowels($string){
    preg_match_all("/[aeiou]/i", $string, $matches);
    return sizeof($matches[0]);
}
echo "Number of vowels : " . countVowels("sUpercalifragilisticexpialidocious");


 

Java:


  public static void main(String[] args) {

        Scanner scan = new Scanner(System.in);
        System.out.println("Type the word:");
        String word = scan.nextLine();

        String[] letters = word.split("");
        int count = 0;

        for (String l : letters) {
            if (l.matches("[aeiouAEIOU]")) {
                count += 1;
            }
        }

        System.out.println("The number of vowels is: " + count);
}

 

ReasonML

Sketch: sketch.sh/s/jjxviGaqjQ2P0ZI0SFC2Sg/

let is_vowel = letter =>
  switch (Char.lowercase_ascii(letter)) {
  | 'a'
  | 'e'
  | 'i'
  | 'o'
  | 'u'
  | 'y' => true
  | _ => false
  };

let explode = s => List.init(String.length(s), String.get(s));

let get_vowel_count = text =>
  text |> explode |> List.filter(is_vowel) |> List.length;

get_vowel_count("hello my name is Earl!");
 

This is very easy in Perl, as the transliteration operator returns the number of matches:

sub vowel_count2 { shift =~ tr/aeiouAEIOU// }

One can also use the Saturn (or Goatse) "secret" operator with a regex match:

sub vowel_count { my $count =()= shift =~ /[aeiou]/gi }

The global match returns all the matches in list context, the assignment to () enforces list context, and enforcing scalar context on it by a scalar assignment returns the number of elements.

 

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.

 

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
 
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

 

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
 
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...

 

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)
 
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);
 

Clojure:

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

Python

def vowel(str): 
    count = 0
    vowels = set("aeiouAEIOU") 
    for alphabet in str: 
        if alphabet in vowels: 
            count = count + 1
    print("No. of vowels :", count) 
str = "The Practical Dev"
vowel(str) 
 

R with some Regex fun:

vowelCounter <- function(s) {
  vowelMatches <- sum(attr(gregexpr("[aeiou]",s, ignore.case = TRUE,
                                    perl= TRUE)[[1]],"match.length"),
                      na.rm = TRUE)
  vowelMatches[vowelMatches == -1 ] <- 0
  return(vowelMatches)
}

 

Python

Given the list :

vowels = ['a', 'e', 'i', 'o', 'u']

We can define a function:

def vowels_count(word):
    count = 0
    for vowel in vowels:
        count += word.lower().count(vowel)
    return count

Or simply in a one-liner:

vowel_count = lambda word: len([char for char in word if char in vowels])
 

C++

int alphaArray [26];

for (int i = 0; i < 26; i++) {
    alphaArray[i] = 0;
}

for (int index = 0; index < userInput.length(); index++) {

    userInput[index] = tolower(userInput[index]);
}

for (int characterIndex = 0; characterIndex < userInput.length(); characterIndex++) {

    alphaArray[userInput[characterIndex] - 97]++;
}

int vowels = alphaArray[0] + alphaArray[4] + alphaArray[8] + alphaArray[14] + alphaArray[20];

cout << "Total number of vowels" << vowels << endl;
cout << "Number of A's: " << alphaArray[0] << endl;
cout << "Number of E's: " << alphaArray[4] << endl;
cout << "Number of I's: " << alphaArray[8] << endl;
cout << "Number of O's: " << alphaArray[14] << endl;
cout << "Number of U's: " << alphaArray[20] << endl;
 

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
 

Shell/awk oneliner:

string="Some random string"
awk '{IGNORECASE=1; print gsub(/a|e|i|o|u/, "")}' <<< $string
 

BASH

echo "some STRING 123 (-_-)" | grep -o -i "[aieou]" | wc -l
 

PHP

function count_vowels(string $str) {
    return preg_match_all('/([aeiou])./', strtolower($str));
}
 

Groovy has a nice built-in Pattern matcher

Integer countVowels(String text) {
    return (text =~ /(?i)[aeiou]/).size()
}
 

Rubeh

require 'set'
vwls = %w"a e i o u".to_set

def sm_vwls(strng)
  strng.chars.sum { |c| vwls.include?(c) }
end
 

Here comes Another 🚀

Python

def challenge3(s):
    s = s.lower()
    N = 0
    for i in s:
        if i in ["a" , "e" , "i" , "o" , "u"]:
            N += 1
    return N
 

Haskell:

import Data.Char

countVowels :: [Char] -> Int
countVowels = length . filter (`elem` "aeiou" ) . map toLower
 
private static List<char> vowels = new List<char>('e','a','i','o','u','E','A','I','O','U');

public static int VowelCount(this string str) => 
    str.Count(c => vowels.Contains(c));
 

Haskell

countVowels :: String -> Int
countVowels = length . filter (flip elem "aeiou")
 

Using Regex in C#

var vowelCount = Regex.Matches(input, @"[AEIOUaeiou]").Count;
 

// Java

public static int countVowels(String input) {
return input.length()-input.replaceAll("(?i)[aeiou]", "").length();
}

 

var vowelCount = Regex.Matches(str, @"[AEIOUaeiou]").Count;
Console.WriteLine(vowelCount);

code of conduct - report abuse