Reputation: 5
I have to write a method called consonant_cancel
that takes in a sentence and returns a new sentence where every word begins with its first vowel. The intended output is for given test functions are:
puts consonant_cancel("down the rabbit hole") #=> "own e abbit ole"
puts consonant_cancel("writing code is challenging") #=> "iting ode is allenging"
But I am getting "own e abbit it ole e"
and "iting ing ode e is allenging enging ing"
with this code.
def consonant_cancel(sentence)
arr = []
vowels = 'aeiou'
words = sentence.split
words.each do |word|
word.each_char.with_index do |char, i|
if vowels.include?(char)
arr << word[i..-1]
end
end
end
return arr.join(' ')
end
puts consonant_cancel("down the rabbit hole") #=> "own e abbit ole"
puts consonant_cancel("writing code is challenging") #=> "iting ode is allenging"
Can you guys help me to debug it?
Upvotes: 0
Views: 80
Reputation: 110725
You can use String#gsub with a regular expression. There is no need to break the string into pieces for processing and subsequent recombining.
def consonant_cancel(str)
str.gsub(/(?<![a-z])[a-z&&[^aeiou]]+/i,'')
end
consonant_cancel("down the rabbit hole")
#=> "own e abbit ole"
consonant_cancel("writing code is challenging")
#=> "iting ode is allenging"
See the section "Character Classes" in the doc for Regexp for an explanation of the &&
operator.
We can write the regular expression in free-spacing mode1 to make it self-documenting.
/
(?<! # Begin a negative lookbehind
[a-z] # Match a lowercase letter
) # End negative lookbehind
[a-z&&[^aeiou]]+ # Match one or more lowercase letters other than vowels
/ix # Invoke case-indifference and free-spacing modes
The negative lookahead ensures that no string of letters immediately preceded by a letter is matched. The line
[a-z&&[^aeiou]]+
can alternatively be written
[b-df-hj-np-tv-z]+
1. See the section "Free-Spacing Mode and Comments" in the doc for Regexp
.
Upvotes: 1
Reputation: 230521
word.each_char.with_index
This loop iterates all chars (and vowels) of the word. break
it after the first vowel found, so it does not repeat the side-effects for subsequent vowels of this word.
As an alternative, here's another regex-based solution
def consonant_cancel(sentence)
sentence.scan(/\b[^aeiou]*(.+?)\b/i).join(" ")
end
Upvotes: 0
Reputation: 36621
If we adding in a puts
to see what's happening in your loop:
def consonant_cancel(sentence)
arr = []
vowels = 'aeiou'
words = sentence.split
words.each do |word|
word.each_char.with_index do |char, i|
if vowels.include?(char)
puts char
arr << word[i..-1]
end
end
end
return arr.join(' ')
end
Then running consonant_cancel "hello world"
we see:
irb(main):044:0> consonant_cancel "hello world"
e
o
o
=> "ello o orld"
irb(main):045:0>
You'll see the same issue with any word with multiple consonants, because of the way you're looping over the characters in a word and checking for consonants.
An easier way to accomplish this would be with regular expressions.
words.split.map { |w| w.sub(/^[^aeiou]*/i, "") }.join(' ')
Upvotes: 0