DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #80 - Longest Vowel Change

The vowel substrings in the word codewarriors are o,e,a,io. The longest of these has a length of 2. Given a lowercase string that has alphabetic characters only and no spaces, return the length of the longest vowel substring. Vowels are any of aeiou.

Good luck!


This challenge comes from KenKamau at CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

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

Top comments (19)

Collapse
 
willsmart profile image
willsmart • Edited

The new JS function matchAll is going to be really useful.
Here's a JS quickie

longestVowelRunLength = string => [...string.matchAll(/[aeiou]+/g)].reduce((acc, [match]) => Math.max(acc, match.length), 0)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
savagepixie profile image
SavagePixie • Edited

Gotta love JavaScript one-liners

const longest = str => str.split(/[^aeiou]+/).reduce((a, b) => b.length > a ? b.length : a, 0)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bhuvan profile image
Bhuvan Ganesan • Edited

Javascript version

longestVowelList = (str) => {
  const vowels = ["a", "e", "i", "o", "u"];
  const result = vowels.map(vowel => {
    const regex = new RegExp(`[^${vowel}]+`);
    return str.split(regex)
       .filter(r => r !== "")
       .sort((a, b) => b.length - a.length);
  });
  return result.flat(1).join("");
}
console.log('---->',longestVowelList("codewarriors"));
//Output ----> aeioo
Collapse
 
kerrishotts profile image
Kerri Shotts

Here's mine... would have liked to use String.prototype.matchAll, but my JS engine didn't support it. So used a generator and Array.from instead. :-)

function *matchAll(str, re) {
    let match;
    do {
        match = re.exec(str);       // get the first match of the regular expession
        if (match) yield match;     // if we have one, yield it
    } while (match != null);        // keep going until no more matches
}

const getLongestSequence = (str, re) =>
    Array.from(matchAll(str, re))   // generators are iterable
         .map(([seq]) => seq)       // extract the string from the regex match result
         .reduce((longest, cur) => 
             cur.length > longest.length ? cur : longest    // keep track of longest
         , "");

const getLongestVowelSequence = str => 
    getLongestSequence(str, /[aeiou]+/gi);  // use vowels -- g = global; i = case insensitive

Full Gist: gist.github.com/kerrishotts/a3ec30...

Collapse
 
kerrishotts profile image
Kerri Shotts

Just noticed that the challenge is to return the length ;-) Oh well -- getLongestVowelSequence("codewarriors").length will do ;-)

Collapse
 
avalander profile image
Avalander • Edited

Haskell

import Data.List (groupBy)

longest :: String -> Int
longest = maximum . map length . filter (isVowel . head) . groupBy bothVowels
  where
    bothVowels a b = (isVowel a) && (isVowel b)

isVowel :: Char -> Bool
isVowel = (flip elem) "aeiou"

longest "codewarriors" -- 2

I could have done it with a single fold, but I decided to group the characters by groups of vowels and non-vowels, filter out the groups that are not vowels, map the length of each group and pick the largest number.

Also, almost entirely point-free, a pity I couldn't figure out how to make bothVowels point-free.

Collapse
 
heidrichj profile image
heidrichj • Edited

Hi,
this is my first time sharing my code here, so please don't judge :)
But I really like these little challenges, thank you!

Here we go (python ftw!):

def vowel(input):
        vowels = ['a','e','i','o','u']
        lengthes = []
        lastVowel = False
        for c in input:
                if c in vowels:
                        if not lastVowel:
                                lengthes +=[1]
                        else:
                                lengthes[len(lengthes)-1] += 1
                        lastVowel = True
                else:
                        lastVowel = False
        return max(lengthes)

print(vowel("codewarriors"))

There is probably some room for improvement...

Have a nice day!

Collapse
 
rafaacioly profile image
Rafael Acioly • Edited

Hi @heidrichj you could also use the class Counter from collections package :)

from typing import Union
from collections import Counter

def vowel(word: str) -> Union[int, None]:
    letters = ('a', 'e', 'i', 'o', 'u')
    letters_on_word = Counter(word)

    for letter, quantity in letters_on_word.most_common():
        if letter in letters:
            return quantity

Tip:

Always use tuple in a list that is "fixed" to ensure that this list will be immutable

Collapse
 
pmkroeker profile image
Peter • Edited

In golang! Could be simpler but lots of loops!

func vowel(input string) string {
    var ls string
    var ret string
    for _, c := range input {
        switch c {
        case 'a', 'e', 'i', 'o', 'u':
            ls += string(c)
        default:
            if len(ls) > len(ret) {
                ret = ls
            }
            ls = ""
        }
    }
    if len(ls) > len(ret) {
        ret = ls
    }

    return ret
}

Go Playground example original
EDIT:
Add new example with changes from comments
Go Playground example with new switch

EDIT 2:
Realized it would not handle vowels at the end of the string
Go Playground

Collapse
 
rafaacioly profile image
Rafael Acioly • Edited

Hey @peter , you can also use multiple values in a single case statement


switch c {
case 'a', 'e', 'i', 'o', 'u':
    ls += string(c)
default:
    arr = append(arr, ls)
    ls = ""
}

github.com/golang/go/wiki/Switch#m...

Collapse
 
pmkroeker profile image
Peter

Hey good to know thanks! Just learning go so didn't realize I could do that. Thanks!

Thread Thread
 
rafaacioly profile image
Rafael Acioly • Edited

there's also strings.Count built-in method ;)

golang.org/pkg/strings/#Count

strings.Count("codewarriors", "a") // 1
Collapse
 
edh_developer profile image
edh_developer • Edited
import re

def longTokenLength(s):
    return max([len(x) for x in re.split("[^aeiou]",s)])

print longTokenLength("codewarriors")

Edit: It being python, I'm condensing my previous code down into a list comprehension.

Collapse
 
dalmo profile image
Dalmo Mendonça • Edited
const longestVowelSequence = (str) => Math.max(...str.split(/[^aeiou]/).map(s => s.length))
Collapse
 
savagepixie profile image
SavagePixie

I like your approach!

Collapse
 
dimitrimarion profile image
Dimitri Marion

Javascript with reduce

const word = "codewarriors"

function findLongestVowels(word) {
  const regex = /[aeiou]/;

  const vowels = Array.prototype.reduce.call(word, 
      (currentLetters, nextLetter, index) => {
       if (regex.test(nextLetter)) {
           return regex.test(word[index-1]) ? 
                    currentLetters.concat('', nextLetter) : 
                    currentLetters.concat(' ', nextLetter);
       } else {
           return currentLetters;
       }
   }, "");

  const longestVowels = vowels.split(' ').reduce( (longest, current) => {
       return current.length > longest.length ? current : longest;
  }, "");

  return longestVowels.length;
}

console.log("Length of the longest vowel: " + findLongestVowels(word));
Collapse
 
aminnairi profile image
Amin

Elm

module Vowel exposing (getLongestVowelSize)


getFirstVowelSubstring : String -> String
getFirstVowelSubstring string =
    case string of
        "" ->
            ""

        _ ->
            let
                first : String
                first =
                    String.left 1 string

                rest : String
                rest =
                    String.dropLeft 1 string
            in
            if List.member first [ "a", "e", "i", "o", "u", "y" ] then
                first ++ getFirstVowelSubstring rest

            else
                ""


getLongestVowel : String -> String -> String
getLongestVowel longest string =
    case string of
        "" ->
            longest

        _ ->
            let
                substring : String
                substring =
                    getFirstVowelSubstring string

                rest : String
                rest =
                    String.dropLeft 1 string
            in
            if String.length longest > String.length substring then
                getLongestVowel longest rest

            else
                getLongestVowel substring rest


getLongestVowelSize : String -> Int
getLongestVowelSize =
    getLongestVowel "" >> String.length

Tests

module VowelTest exposing (suite)

import Expect exposing (equal)
import Test exposing (Test, describe, test)
import Vowel exposing (getLongestVowelSize)


suite : Test
suite =
    describe "Vowel"
        [ test "Should return 0 for a string with no vowels" <|
            \_ -> equal 0 <| getLongestVowelSize "bcdfgh"
        , test "Should return 1 for a string with a one-vowel substring" <|
            \_ -> equal 1 <| getLongestVowelSize "abcdefghij"
        , test "Should return 2 for a string with a two-vowel substring" <|
            \_ -> equal 2 <| getLongestVowelSize "codewarriors"
        ]
Collapse
 
jaumevn profile image
Jaume Viñas Navas • Edited

This is the Swift version :)

func longestVowelSubstring(s: String) -> Int {
    let vowels: [Character] = ["a", "e", "i", "o", "u"]
    var max = 0
    var aux = 0

    for (_,char) in s.enumerated() {
        if (vowels.contains(char)) {
            aux += 1
            max = max < aux ? aux : max
        } else {
            aux = 0
        }
    }

    return max
}
Collapse
 
choroba profile image
E. Choroba • Edited

Perl solution, tests included.

#!/usr/bin/perl
use warnings;
use strict;

sub longest_vowel_substring {
    my ($string) = @_;
    my $max_length = 0;
    $max_length < length $1 and $max_length = length $1
        while $string =~ /([aeiou]+)/g;
    $max_length
}

use Test::More tests => 2;
is longest_vowel_substring('codewarriors'), 2;
is longest_vowel_substring('xaaeexaeiooxxaxax'), 5;