patternrubyMinor
Determine a poem's rhyme scheme
Viewed 0 times
schemepoemrhymedetermine
Problem
The TopCoder question specifies (in summary):
Two words are considered rhyming if they have the same ending pattern (defined below). This comparison is case-insensitive (see Example 1.)
An ending pattern is a substring of a word such that:
For example, the ending pattern of "bought" is "ought", the ending pattern of "spying" would be "ying", and the ending pattern of "all" would be "all". (Note that "spy" has no vowels, and thus is not a legal word.)
Example 1:
Returns:
Even though "height" and "weight" don't actually rhyme in English, they do by the rules laid out above.
I want to get general feedback and feedback about if I can make this more Ruby-like, if there are any obvious inefficiencies, and if I need to organize my class differently.
```
#!/usr/bin/env ruby -w
require 'set'
class Poetry
def find_ending(str)
vowels = Set.new(['a', 'e', 'i', 'o', 'u'])
vowel_seen = false
ending = ""
str.reverse.each_char.with_index do |c, i|
if vowels.include?(c) or
(c == 'y' and i != 0 and i != str.length-1)
vowel_seen = true
ending = c + ending
elsif !vowel_seen
ending = c + ending
else
break
end
end
ending
end
def rhyme_scheme(poem_array)
scheme = ""
next_label = 'a'
ending_labels = {}
poem_array.each do |line|
if line.strip.empty?
scheme += ' '
else
word = line.split(' ')[-1]
ending = self.find_ending(wo
Two words are considered rhyming if they have the same ending pattern (defined below). This comparison is case-insensitive (see Example 1.)
An ending pattern is a substring of a word such that:
- The word ends with that substring,
- The substring contains exactly one contiguous string of vowels,
- The first letter of the substring is a vowel, and
- The substring must either be the whole string, or the letter immediately preceding the start of the substring must be a nonvowel.
For example, the ending pattern of "bought" is "ought", the ending pattern of "spying" would be "ying", and the ending pattern of "all" would be "all". (Note that "spy" has no vowels, and thus is not a legal word.)
Example 1:
{" ",
"Measure your height",
"AND WEIGHT ",
"said the doctor",
"",
"And make sure to take your pills",
" to cure your ills",
"Every",
"DAY"}Returns:
" aab ccde"Even though "height" and "weight" don't actually rhyme in English, they do by the rules laid out above.
I want to get general feedback and feedback about if I can make this more Ruby-like, if there are any obvious inefficiencies, and if I need to organize my class differently.
```
#!/usr/bin/env ruby -w
require 'set'
class Poetry
def find_ending(str)
vowels = Set.new(['a', 'e', 'i', 'o', 'u'])
vowel_seen = false
ending = ""
str.reverse.each_char.with_index do |c, i|
if vowels.include?(c) or
(c == 'y' and i != 0 and i != str.length-1)
vowel_seen = true
ending = c + ending
elsif !vowel_seen
ending = c + ending
else
break
end
end
ending
end
def rhyme_scheme(poem_array)
scheme = ""
next_label = 'a'
ending_labels = {}
poem_array.each do |line|
if line.strip.empty?
scheme += ' '
else
word = line.split(' ')[-1]
ending = self.find_ending(wo
Solution
I am a bit late, I hope the answer is still useful. Some notes:
I'd write (second approach):
- First, my tradicional advice: don't use imperative programming! I mean, it's ok if you are writing assembler or C, but in a language like Ruby you're squandering its potential. Try to learn to program in functional style, favouring the good old math expressions (with its abstractions, immutability, higher-order functions, modulatization and many other cool things).
- I'd use regular expressions to get the rhyming substring of each verse, no custom code can beat their compactness and expression power.
- There are two ways of solving the problem, one is traversing the verses only once, folding the verses into an output. The second one is more modular, traverse the verses to build the intermediate data structures needed to calculate the solution. This second approach is, in this case, less verbose.
I'd write (second approach):
def rhyme_scheme(verses)
ending_regexp = /((?:[aeiou]|\By\B)+[^aeiou]*)$/
endings = verses.map { |verse| verse.strip.downcase[ending_regexp, 1] }
ending_scheme_pairs = endings.uniq.compact.zip([*"a".."z", *"A".."Z"])
schemes = ending_scheme_pairs.to_h.merge(nil => " ")
schemes.values_at(*endings).join
endCode Snippets
def rhyme_scheme(verses)
ending_regexp = /((?:[aeiou]|\By\B)+[^aeiou]*)$/
endings = verses.map { |verse| verse.strip.downcase[ending_regexp, 1] }
ending_scheme_pairs = endings.uniq.compact.zip([*"a".."z", *"A".."Z"])
schemes = ending_scheme_pairs.to_h.merge(nil => " ")
schemes.values_at(*endings).join
endContext
StackExchange Code Review Q#26541, answer score: 9
Revisions (0)
No revisions yet.