Ordered Vowels
January 31, 2017
Today’s exercise is to write a program that finds all the words in a dictionary in which all the vowels in the word appear in ascending order. It is not necessary that all five vowels appear in the word, and vowels may be doubled. For instance, afoot
passes because the three vowels, a
, o
and o
appear in non-decreasing order.
An easy way to solve this problem uses regular expressions:
$ grep '^[^aeiou]*a*[^aeiou]*e*[^aeiou]*i*[^aeiou]*o*[^aeiou]*u*[^aeiou]*$' /etc/dict/words
Since that is so easy, you must write a program that does not use regular expressions.
Your task is to write a program that finds words with ordered vowels. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Your regex doesn’t seem to handle doubled vowels separated by non-vowels, like, ALBATROS
so something like that may be more accurate: ‘^([^aeiou]*a)*([^aeiou]*e)*([^aeiou]*i)*([^aeiou]*o)*([^aeiou]u*)*[^aeiou]*$’
also, in some languages “y” is also a vowel. (not in english?)
In Python.
A finite-state automaton then, for the Finnish set of vowel characters.
Testing with a 1916 translation of Homer’s Odysseus from Project Gutenberg,
recall looks about right:
An implementation in Julia, from scratch (i.e. no external libraries whatsoever). Using the complete scrabble dictionary (~173K words), it took a little over a second to work out all the words with ascending vowels and store them in a string array. I also added an auxiliary function to retrieve the dictionary words from the text file I’ve put them in. Here is the source code:
function GetWordsFromDictionary{T <: AbstractString}(fn::T = "D:\\data\\words.txt")
f = open(fn)
words = split(readall(f), ",")
close(f)
return words
end
function ascending(v::Array{Char, 1})
n = length(v)
for i = 2:n
if v[i] < v[i-1]; return false; end
end
return true
end
function AllVowels{T 0]
vowels = Array(Char, n)
for i = 1:n
vowels[i] = word[ind[i]]
end
return vowels
end
function vao{T <: AbstractString}(words::Array{T, 1}) # this is the main function
n = length(words)
ind = falses(n)
for i = 1:n
ind[i] = ascending(AllVowels(words[i]))
end
return words[ind]
end
Probably not the most elegant solution, but I prefer to keep the code in a modular format so that I can reuse parts of it in other scripts (something quite common in functional languages).
Here’s a Haskell version. You supply an ascending list of vowels as a command-line argument. The function hasOrderedSubsequence works for any type that supports equality, not just characters. I’ve included the output of two runs: one with English vowels (I don’t count ‘y’) on the Mac dictionary, another with Finnish vowels (taken from Jussi’s program) on the same translation of Homer’s Odyssey.