loading...

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
 

JavaScript:

f=s=>s.match(/[aeiou]/gi).length

Demo on CodePen.

 

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.

 

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

 

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

 

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

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

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

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

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.

 

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

 

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 }
 

Python regex example

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

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
}
 

A little late to the party, but this is my JavaScript solution:

function vowelCounter(text) {
  const letters = text.toLowerCase().split('');
  const count = [...'aeiou'].map(vowel => 
    letters.filter(letter => letter === vowel)).flat().length;
  return count;
}

 

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

 

In F#

let isVowel (c:char) =
    match c.ToString().ToLowerInvariant() with
    | "a" | "e" | "i" | "o" | "u" -> 1
    | _ -> 0

let vowelCount (s:string) = s.ToCharArray() |> Array.sumBy(fun x -> isVowel x)

printfn "%d" (vowelCount "The cUnNinG fOx jumpEd over the lazy dog - twice!")
 

//TS

my solution with TDD:

test:

import vowelCounter from './vowel-counter';

describe('tdd vowel counter', () => {
    test('should be 0 if empty string', () => {
        expect(vowelCounter('')).toEqual(0);
    });
    test('should be return counter', () => {
        expect(vowelCounter('aWscErvO')).toEqual(3);
        expect(vowelCounter('aaaa')).toEqual(4);
        expect(vowelCounter('IIIII')).toEqual(5);
        expect(vowelCounter('AEr#_%^&tioCda')).toEqual(5);
    });
});

and func


export default (str: string): number =>
    str
        .toLowerCase()
        .split('')
        .filter(val => ['a', 'e', 'i', 'o', 'u'].includes(val)).length;
 

Dart

import 'dart:io';

main(){
  stdout.writeln('Phrase?');
  String phrase = stdin.readLineSync();
  var regExp =  RegExp(r'[aeiou]');
  phrase.length > 2 ? print("Vocal count: " + regExp.allMatches(phrase.toLowerCase()).length.toString()) : print('Invalid Phrase');
}
 

Powershell

I do try to keep it as an actual function and give pretty/usable output.

function Get-VowelCount {
    param(
        [string]$InString
    )

    [pscustomobject]@{
        String              = $InString
        LowerCaseCount = [regex]::Matches($InString,'[aeiou]').Count
        UpperCaseCount = [regex]::Matches($InString, '[AEIOU]').count
    }
}
 

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

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


 
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

 

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

 

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
 

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;
 

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

Haskell:

import Data.Char

countVowels :: [Char] -> Int
countVowels = length . filter (`elem` "aeiou" ) . map toLower
 

Groovy has a nice built-in Pattern matcher

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

Haskell

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

Rubeh

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

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

Ruby

def vowel_count(text)
  text.scan(/([aeiou])/i).size
end


puts vowel_count("Hello World!!!!") #3
 

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
 

Using Regex in C#

var vowelCount = Regex.Matches(input, @"[AEIOUaeiou]").Count;
 
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));
 

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