object PigLatin {
private val vowels = Set('a', 'e', 'i', 'o', 'u')
private val vowels_y = Set('a', 'e', 'i', 'o', 'u', 'y')
private val specials = Set("xr", "yt")
def translate(phrase: String): String = {
phrase
.split(" ")
.map(word =>
if (vowels.contains(word.head) || specials.contains(word.slice(0, 2)))
word + "ay"
else findVowel(word, 1)
)
.mkString(" ")
}
@scala.annotation.tailrec
private def findVowel(word: String, pos: Int): String = {
word.charAt(pos) match {
case ltr if vowels_y.contains(ltr) => {
val posFix = if (word.slice(pos - 1, pos + 1) == "qu") pos + 1 else pos
word.slice(posFix, word.length()) + word.slice(0, posFix) + "ay"
}
case _ => findVowel(word, pos + 1)
}
}
}
This approach starts by defining some Sets to to hold the vowels, vowels with y
, and the special groups of letters.
The input phrase is split on a space character and the word or words are chained to the map()
method.
Each word is passed to the lambda which consists of an if/else
expression.
If the Set
of vowels includes the first character of the word (also called the head
), or if a slice()
of the first two characters is one of the special groups of letters, then map()
outputs the word appended with ay
.
Otherwise, the findVowel()
method is passed the word and a starting position of 1
.
The findVowel()
method is annotated with the @tailrec
annotation to verify that the method can be compiled
with tail call optimization.
A tail call is a particular form of recursion where the last call in the method is a call to the same method and nothing else.
In other words, if the last call in recurMe()
is recurMe(arg1, arg2) + 1
, the + 1
makes the recursion non-tail recursive.
If the last call in recurMe()
is recurMe(arg1, arg2, acc + 1)
, then the recursion is a tail call, because only the method is being called
with no other operation being peformed on it.
A match
expression is used to perform pattern matching on the result of passing the position
to the charAt()
method.
A pattern guard is used to check if the character is a vowel (y
is considered a vowel at this point.)
If so, the positon is adjusted if the previous character and the current character are qu
, otherwise it stays the same.
The match
returns a slice()
from the position until the end of the word, to which is concatenated a slice()
from the
beginning of the word up to but not including the character at the position, to which is concatenated ay
.
If the character is not a vowel, then findVowel()
calls itself, passing in the same word and adding 1
to the position.
After all of the words have been mapped, they are reassembled into a string by the mkString()
method.