How do I count vowels? - ruby

I've seen the solution and it more or less matches
Write a method that takes a string and returns the number of vowels
in the string. You may assume that all the letters are lower cased. You can treat "y" as a consonant.
Difficulty: easy.
def count_vowels(string)
vowel = 0
i = 0
while i < string.length
if (string[i]=="a" || string[i]=="e" || string[i]=="i" || string[i]=="o"|| string[i]=="u")
vowel +=1
end
i +=1
return vowel
end
puts("count_vowels(\"abcd\") == 1: #{count_vowels("abcd") == 1}")
puts("count_vowels(\"color\") == 2: #{count_vowels("color") == 2}")
puts("count_vowels(\"colour\") == 3: #{count_vowels("colour") == 3}")
puts("count_vowels(\"cecilia\") == 4: #{count_vowels("cecilia") == 4}")

def count_vowels(str)
str.scan(/[aeoui]/).count
end
/[aeoui]/ is a regular expression that basically means "Any of these characters: a, e, o, u, i". The String#scan method returns all matches of a regular expression in the string.

def count_vowels(str)
str.count("aeoui")
end

Your function is fine you are just missing a keyword end to close of your while loop
def count_vowels(string)
vowel = 0
i = 0
while i < string.length
if (string[i]=="a" || string[i]=="e" || string[i]=="i" || string[i]=="o"|| string[i]=="u")
vowel +=1
end
i +=1
end
return vowel
end
puts("count_vowels(\"abcd\") == 1: #{count_vowels("abcd") == 1}")
puts("count_vowels(\"color\") == 2: #{count_vowels("color") == 2}")
puts("count_vowels(\"colour\") == 3: #{count_vowels("colour") == 3}")
puts("count_vowels(\"cecilia\") == 4: #{count_vowels("cecilia") == 4}")
#=> count_vowels("abcd") == 1: true
#=> count_vowels("color") == 2: true
#=> count_vowels("colour") == 3: true
#=> count_vowels("cecilia") == 4: true

I think using HashTable data structure would be good way to go for this particular problem. Especially if you're required to output number of every single vowel separately.
Here is the code I'd use:
def vowels(string)
found_vowels = Hash.new(0)
string.split("").each do |char|
case char.downcase
when 'a'
found_vowels['a']+=1
when 'e'
found_vowels['e']+=1
when 'i'
found_vowels['i']+=1
when 'o'
found_vowels['o']+=1
when 'u'
found_vowels['u']+=1
end
end
found_vowels
end
p vowels("aeiou")
Or even this (elegant but not necessarily performant):
def elegant_vowels(string)
found_vowels = Hash.new(0)
string.split("").each do |char|
case char.downcase
when ->(n) { ['a','e','i','o','u'].include?(n) }
found_vowels[char]+=1
end
end
found_vowels
end
p elegant_vowels("aeiou")
which would output:
{"a"=>1, "e"=>1, "i"=>1, "o"=>1, "u"=>1}

So you don't have to turn the string into an array and worry about case sensitivity:
def getVowelCount(string)
string.downcase.count 'aeiou'
end

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.

Question on how to filter x || y and not x && y

I am having trouble using || ("or").
This is the first time I select using the "or" feature and I have been trying to select the words that are greater than 6 characters long OR start with an "e". I tried everything but I keep getting just one feature or an "and". This is the code so far
def strange_words(words)
selected_words = []
i = 0
while i < words.length
word = words[i]
if word.length < 6
selected_words << word
end
i += 1
end
return selected_words
end
print strange_words(["taco", "eggs", "we", "eatihhg", "for", "dinner"])
puts
print strange_words(["keep", "coding"])
Using the || operator is the same as writing multiple if statements. Let's use a silly example to demonstrate it. Say you wanted to determine if a word started with the letter 'e'. Well there are a few forms of 'e'. There is the lowercase e and the upppercase E. You want to check for both forms so you could do something like this:
def starts_with_e?(string)
result = false
if string[0] == 'e'
result = true
end
if string[0] == 'E'
result = true
end
result
end
Notice however that you're doing the same actions after checking for the condition. This means you could simplify this code using the OR/|| operator, like such:
def starts_with_e?(string)
result = false
if string[0] == 'e' || string[0] == 'E'
result = true
end
end
For your specific question, you can do the following:
def strange_words(words)
words.select { |word| word.length < 6 || word[0] == 'e' }
end
When you run with your example, it gives you this output:
> strange_words(["taco", "eggs", "we", "eatihhg", "for", "dinner"])
=> ["taco", "eggs", "we", "eatihhg", "for"]
This is still not good code. You'll want to protect the methods from bad input.

String compressor (Ruby)

Here is my code in ruby for a word compression.
For any given word (e.g. abbbcca) the compressed word/output should be in the format as "letter+repetition" (for above example, output: a1b3c2a1).
Here I'm so close to the completion but my result isn't in the expected format. It's counting the whole letters in string.chars.each thus resulting output as a2b3c2a2.
Any help?
def string_compressor(string)
new_string = []
puts string.squeeze
string.squeeze.chars.each { |s|
count = 0
string.chars.each { |w|
if [s] == [w]
count += 1
end
}
new_string << "#{s}#{count}"
puts "#{new_string}"
}
if new_string.length > string.length
return string
elsif new_string.length < string.length
return new_string
else "Equal"
end
end
string_compressor("abbbcca")
'abbbcca'.chars.chunk{|c| c}.map{|c, a| [c, a.size]}.flatten.join
Adapted from a similar question.
Similar:
'abbbcca'.chars.chunk{|c| c}.map{|c, a| "#{c}#{a.size}"}.join
See chunk documentation
You can use a regular expression for that.
'abbbcca'.gsub(/(.)\1*/) { |m| "%s%d" % [m[0], m.size] }
#=> "a1b3c2a1"
The regular expression reads, "match any character, capturing it in group 1. Then match the contents of capture group 1 zero or more times".
As you said, your code counts every letter in the string, not just the one grouped next to one another.
Here's a modified version :
def display_count(count)
if count == 1
""
else
count.to_s
end
end
def string_compressor(string)
new_string = ''
last_char = nil
count = 0
string.chars.each do |char|
if char == last_char
count += 1
else
new_string << "#{last_char}#{display_count(count)}" if last_char
last_char = char
count = 1
end
end
new_string << "#{last_char}#{display_count(count)}" if last_char
new_string
end
p string_compressor('abbbcca') #=> "ab3c2a"
p string_compressor('aaaabbb') #=> "a4b3"
p string_compressor('aabb') #=> "a2b2"
p string_compressor('abc') #=> "abc"
Note that with display_count removing 1s from the string, new_string can never be longer than string. It also probably isn't a good idea to return Equal as a supposedly compressed string.
To decompress the string :
def string_decompressor(string)
string.gsub(/([a-z])(\d+)/i){$1*$2.to_i}
end
p string_decompressor("a5b11") #=> "aaaaabbbbbbbbbbb"
p string_decompressor("ab3c2a") #=> "abbbcca"

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

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

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!

Resources