loading...

Daily Challenge #80 - Longest Vowel Change

thepracticaldev profile image dev.to staff ・1 min read

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!

Discussion

pic
Editor guide
Collapse
bhuvan profile image
Bhuvan Ganesan

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
savagepixie profile image
SavagePixie

Gotta love JavaScript one-liners

const longest = str => str.split(/[^aeiou]+/).reduce((a, b) => b.length > a ? b.length : a, 0)
Collapse
willsmart profile image
willsmart

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

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
pmkroeker profile image
Peter

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

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

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

golang.org/pkg/strings/#Count

strings.Count("codewarriors", "a") // 1
Collapse
heidrichj profile image
heidrichj

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

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
edh_developer profile image
edh_developer
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
jaumevn profile image
Jaume Viñas Navas

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

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;
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
dalmo profile image
Dalmo Mendonça
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));