What's wrong with this Ruby program that counts vowels? - ruby

When I test this program on strings the output is 0. I think my logic is sound and it's just a minor syntax thing. Anyone see the problem?
def VowelCount(string)
string.downcase
i = 0
vowels = 0
until i == string.length-1
if (string[i] == "a" || string[i] == "o" || string[i] == "e" || string[i] == "i" || string[i] == "u")
vowels += 1
end
i += 1
end
return vowels
end

You can use String#count:
str = "It was the best of times, it was the worst of times,..."
str.downcase.count('aeiou') #=> 14

The following line
until i == string.length-1
should be:
until i == string.length
Otherwise, the last character is not checked.
BTW, by convension, method name starts with lower case, and combined with underscore. Here's an alternative solution using regular expression.
def vowel_count(string)
string.scan(/[aeiou]/i).length
end
update
As JesseSielaff pointed, String#downcase does not change the string in place. You need to assign the return value of the method back or use String.downcase!

Related

if statement doesn't get executed in Ruby

I'm new to Ruby programming language and i am asked to make a small program that does the following:
Rule 1: If a word begins with a vowel sound, add an "ay" sound to the end of the word.
Rule 2: If a word begins with a consonant sound, move it to the end of the word, and then add an "ay" sound to the end of the word.
but in my if else statement it doesn't go into the if even if its true it stays at the else statement
i have tried taking the string and converting it into an array and work on the array and tried working on the string as is
def translate (str)
i = 0
while i < str.length
if (str[i] == "a" or str[i] == "e" or str[i] == "o" or str[i] == "u" or str[i] == "i")
str = str + "ay"
return str
else
temp = str[0...1]
str = str[1...str.length]
str = str + temp
end
i = i + 1
end
end
s = translate("banana")
puts s
the program doesn't enter the if statement at all and keeps getting into the else statement until the word returns the same with out any changes
Aside from my suggestion to use || instead of or, your method doesn't need a #while iterator since you're checking only for the first letter. The if/else statement should be executed only once.
You can also replace all the checks with a single #include? method like this:
def translate (str)
if %w[a e i o u].include?(str[0])
str + "ay"
else
str[1..-1] + str[0] + "ay"
end
end
Notice that I've also removed the return statement since the last executed line will be returned, so either line 3 or line 5 in the method above.
You can also add a ternary operator to make it in one line:
%w(a e i o u).include?(str[0]) ? str + "ay" : str[1..-1] + str[0] + "ay"
Rule 1: If a word begins with a vowel sound, add an "ay" sound to the
end of the word.
translate("ana")
# ~> "anaay"
Rule 2: If a word begins with a consonant sound, move it to the end of
the word, and then add an "ay" sound to the end of the word.
translate("banana")
# ~> "ananabay"
If I understand the problem correctly, you do not need to loop at all here. You just need to check the first letter, and not all of the letters.
def translate (str)
if str[0] == 'a' or str[0] == 'e' or str[0] == 'o' or str[0] == 'u' or str[0] == 'i'
str + 'ay'
else
temp = str[0...1]
str = str[1...str.length]
str = str + temp
str + 'ay'
end
end
By the way, I was able to figure this out with the debugger. Did you try that at all? Also, with your original code it turns out that for some inputs (like 'baaan'), your else statement does execute.
I don't see a problem with or or || in this case.
The problem I see is that if the start letter is a consonant, you changing str rotating it's letters at each iteration (see the commented part of the code), so the starting letter is never a vowel.
Then you are missing a returning value at the end so it returns nil and puts nothing.
def translate (str)
i = 0
while i < str.length
p str[i] # it's never a vowel
if (str[i] == "a" or str[i] == "e" or str[i] == "o" or str[i] == "u" or str[i] == "i")
str = str + "ay"
return str
else # here you are rotating the word
temp = str[0...1]
str = str[1...str.length]
str = str + temp
p str
end
i = i + 1
end
# missing a return value
end
s = translate("banana")
p s
So it prints out:
# "b"
# "ananab"
# "n"
# "nanaba"
# "n"
# "anaban"
# "b"
# "nabana"
# "n"
# "abanan"
# "n"
# "banana"
# nil
The code works correctly in case the first letter is a vowel, so it enters the if true:
s = translate("ananas")
p s
#=> "ananasay"
By the way, as already posted by others, you don't need any while loop. Just checking the first letter with an if statement is enough.

Ruby: Reverse method from scratch

I'm working on a coding challenge practice problem that is asking me to put together a method that reverses a string and have come up with:
def reverse(string)
idx = 1
array_s = []
while idx <= string.length
array_s.push(string[string.length - idx])
idx = idx + 1
end
new_string = array_s.join("")
puts new_string
end
When I run the test given at the end,
puts(
'reverse("abc") == "cba": ' + (reverse("abc") == "cba").to_s
)
puts(
'reverse("a") == "a": ' + (reverse("a") == "a").to_s
)
puts(
'reverse("") == "": ' + (reverse("") == "").to_s
)
it seems to show that the strings reverse, but it still prints false. Is there anything I'm missing in the method I wrote? Thanks.
Your function is working as expected, it is the last line that is causing you issues.
puts new_string
puts returns nil, ruby uses implicit returns unless you explicitly say return, so it returns the result from the last line of code, in this case is nil.
If you just do new_string or return new_string, it will work.
Or if you want to print it to the screen and return it as the result, you can do
p new_string
davidhu2000 has answered your question correctly but i would suggest refactoring the code:
f = "forward"
puts f.reverse
# drawrof
of if you really want:
def reverse(string)
return string.reverse
end

ruby returning true if a string consists an "a" and then a "z"

I need help on Writing a method that takes a string in and returns true if the letter "z" appears within three letters after an "a". You may assume that the string contains only lowercase letters. here's what I have:
def nearby_az(string)
string.downcase!
i = 0
while i < string.length
if (string[i] == "a" && string[i] == "z")
true
else
false
end
end
end
puts('nearby_az("baz") == true: ' + (nearby_az('baz') == true).to_s)
puts('nearby_az("abz") == true: ' + (nearby_az('abz') == true).to_s)
puts('nearby_az("abcz") == true: ' + (nearby_az('abcz') == true).to_s)
puts('nearby_az("a") == false: ' + (nearby_az('a') == false).to_s)
puts('nearby_az("z") == false: ' + (nearby_az('z') == false).to_s)
puts('nearby_az("za") == false: ' + (nearby_az('za') == false).to_s)
A regular expression would be the best for this. Try
def nearby_az(string)
(string =~ /a.{0,2}z/) != nil
end
EDIT:
as per the "if statement required requirement" :)
def nearby_az(string)
if (string =~ /a.{0,2}z/) != nil
return true
end
return false
end
The way this code works is it searches the input string for an "a". After that, the period indicates that you can have any character. After that you have {0,2} which is a modifier of the period indicating you can have 0 to 2 of any character. After this you must have a "z", and this fulfills your must have a z within 3 characters of an "a".
I've saved this regex to regex101 here so you can try various inputs as well as change the regular expression around to understand it better.
To fix you code you need to:
increment i at the end of the loop.
search the z letter within the 3 next letters
return true when condition is met
return false when getting out of the loop
Here is what it should look like:
def nearby_az(string)
string.downcase!
i = 0
while i < string.length do
return true if string[i] == "a" && string[i+1,3].include?(?z)
i+=1
end
return false
end

Ruby code for deleting the vowels in a string

I'm trying to write code in Ruby that removes all the vowels from a string:
def remvowel(string)
i = 0
dv_string = []
while i < string.length
if (string[i] != "a" || string[i] != "e" || string[i] != "i" || string[i] != "o" || string[i] != "u")
dv_string.push(i)
i += 1
end
i += 1
end
return dv_string.join
end
But it's not coming out right. When I run remvowel("duck"), it returns "02", as in the index positions of "dc". I'm missing something, but I don't know what.
You could just:
string.gsub(/[aeiou]/, '')
Or even better:
string.tr('aeiou', '')
And the best tool for deleting characters in a string is...
string.delete('aeiou')
That's because you're pushing i instead of string[i].
dv_string.push(i)
This is what you want:
dv_string.push(string[i])
However, that's a rather verbose and roundabout way of accomplishing the task. A somewhat more idiomatic Ruby approach would look like any of the ones ndn posted:
def remvowel(string)
string.gsub /[aeiou]/, ''
end
or
def remvowel(string)
string.tr 'aeiou',''
end
or
def remvowel(string)
string.delete 'aeiou'
end
You've got it almost right:
def remvowel(string)
i = 0
dv_string = []
while i < string.length
if (string[i] != "a" || string[i] != "e" || string[i] != "i" || string[i] != "o" || string[i] != "u")
# Push the letter, not i
dv_string.push(string[i])
# Don't increment i here
end
i += 1
end
return dv_string.join
end
Your algorithm increments i twice if you encounter a consonant, so you are skipping every second letter.
Here is one more way this can be done:
s = "Hello, how are you you?"
vowels = "aeiou"
puts (s.chars - vowels.chars).join
#=> Hll, hw r y y?
Thank you everybody for your contributions. Thanks to you all (and especially you, Cary Swoveland), I not only know better ways to do this in the future, but even found an answer for my "scenic route" way of doing it!
def remvowel(string)
i = 0
dv_string = []
while i < string.length
dv_string.push(string[i])
if (string[i] == "a" || string[i] == "e" || string[i] == "i" || string[i] == "o" || string[i] == "u")
dv_string.delete(string[i])
end
i += 1
end
return dv_string.join
end
Granted, I'm gonna be doing the more sensible way from the responses here from now on, but mission accomplished!

Why can't I find `"az"` in a string with this function?

I want to know if "a" and "z" are together in a string after I have found "a". I'd like to understand why this does not work:
def nearby_az(string)
i = 0
while i < string.length
if string[i] == "a" && string[i+1] == "z"
return true
else
return false
end
i += 1
end
end
I realize there is a simple way to implement this. I am not looking for another solution.
This code will only find "az" if it's at the very beginning. Otherwise it will return false. Postpone return false until you walked the whole string.
def nearby_az(string)
i = 0
while i < string.length -1
return true if string[i] == "a" && string[i+1] == "z"
i += 1
end
# we can only reach this line if the loop above does not return.
# if it doesn't, then the substring we seek is not in the input.
return false
end
nearby_az('baz') # => true
#Segio Tulentsev' s answer explains why yours is broken.
Here's the short implementation if you're interested
def nearby_az(str)
!! str =~ /a(?=z)/i
end

Resources