What is wrong with my Ruby vowel-counting loop? [closed] - ruby

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to create a loop that add 1 to the idx every time theres a vowel in the string, but my code returns nothing.
def count_vowels(string)
vowlcounter = 0
idx = 0
words = string.split('')
while idx < string.length
if words[idx] == 'a'||'e'||'i'||'o'||'u'
vowlcounter += 1
idx += 1
end
end
return vowlcounter
end

You can use Regular expressions for shorter comparison if the string or char is a vowel. The other way like you wanted to would be way too long:
if words[idx] == 'a' || words[idx] == 'e'
And so on ...
Also if you would just increment idx everytime you have actually a vowel, you would get stuck in an infinite loop if the char isnt a vowel, idx would not increase, thus always checking for the same value in the while loop.
This code works by using Regular expression:
def count_vowels(string)
vowlcounter = 0
idx = 0
while idx < string.length
if string[idx][/[aeiou]/]
vowlcounter += 1;
end
idx += 1;
end
return vowlcounter
end

Scan and Count Vowels
This strikes me as an X/Y problem. Rather than debugging your code, it may be better to simply use built-in String methods to count your vowels, rather than doing your own iteration through the string. Other people can address the Y in your X/Y problem, but I'd rather help you solve for X directly.
Using String#scan
Use String#scan and Array#count to do this quickly and easily. While this doesn't account for y when used as a vowel, it should otherwise do what you want.
def vowel_count str
str.scan(/[aeiou]/).count
end
vowel_count 'foo'
#=> 2
vowel_count 'foo bar baz'
#=> 4
Using String#count
I like using #scan best, because it returns an array you can use elsewhere if you like and helps with debugging. However, if you don't care about which vowels are found, you can use the String#count method directly. For example:
def vowel_count str
str.count 'aeiou'
end
vowel_count 'foo'
#=> 2
vowel_count 'foo bar baz'
#=> 4
The results are the same, but you loose the ability to introspect the values returned inside your method. YMMV.

Related

How to remove 3 or more the same character

During my lessons of Ruby I came across of this exercise. I'm trying to remove 3 or more the same charactes in a row. Test Cases Input: abbbaaccada Output: ccada Input: bbccdddcb Output: (Empty string)
So far I have solution which doesn't return expected results:
def playground("abbbaaccada")
count = string.length
string.chars.each_with_index.map { |v, i| (v * (count - i)).capitalize }.join('')
end
output gives me
==> AaaaaaaaaaaBbbbbbbbbbBbbbbbbbbBbbbbbbbAaaaaaaAaaaaaCccccCcccAaaDdA
instead of
==> ccada
Could you please advise?
Edit:
Forgot to add that regexp isn't allowed
There are two challenges here:
Match and remove any run of thee or more characters in a row
Recurse to test again in case the previous step created a new run of three
Here's one way to do it:
THREE_OR_MORE = /(.)\1{2,}/
def three_is_too_many(str)
if str.match? THREE_OR_MORE
str = three_is_too_many(str.gsub(THREE_OR_MORE, ''))
end
str
end
The regexp finds any character ('.'), followed by itself ('\1'), two or more times ('{2,}').
Then the routine either a) removes three or more and tests again or b) returns the string.
Here's a potential solution. The following method searches for any subsequence of an array with repeats, and returns the range of the repeated values if there are three or more of them.
def find_3_or_more(ary)
ary.each_index do |i|
j = i + 1
while j < ary.length && ary[i] == ary[j]
j += 1
end
return (i...j) if j - i > 2
end
nil
end
This portion breaks the target string into an array of chars, and repeatedly slices out the characters in ranges identified as repeats until there are none, as indicated by a nil range.
def delete_3_or_more(str)
ary = str.chars
while r = find_3_or_more(ary)
ary.slice!(r)
end
return ary.join
end
It seems to do the job for your test cases.
def recursively_remove_runs_of_3_or_more(str)
arr = str.chars
loop do
a = arr.slice_when { |a,b| a.downcase != b.downcase }.to_a
b = a.reject! { |e| e.size > 2 }
arr = a.flatten
break arr.join if b.nil?
end
end
recursively_remove_runs_of_3_or_more "abbbaaccada"
#=> "ccada"
This uses Enumerable#slice_when (new in MRI v2.2). Note that Array#reject! returns nil when no changes are made.
You could alternatively use Enumerable#chunk_while (new in MRI v2.3). Simply replace:
a = arr.slice_when { |a,b| a.downcase != b.downcase }.to_a
with:
a = arr.chunk_while { |a,b| a.downcase == b.downcase }.to_a
chunk_while and slice_when are yin and yang.
If a regular expression could be used and case where not an issue, you could write:
str = "abbbaaccada"
s = str.dup
loop { break(s) if s.gsub!(/(.)\1{2,}/, '').nil? }
#=> "ccada"
(I wanted to comment, but it doesn't allow me to do that yet.)
Assuming that you are trying to learn, I chose to only give you some tips while avoiding a solution.
There might be shorter ways of doing this using regex or/and some String methods. However, you said you can not use regex.
My tip is, try to solve it only using the sections you have covered so far. It may not necessarily be the most elegant solution, but you can revise it as you progress. As others suggested, recursion might be a good option. But, if you are not familiar with that yet, you can try slicing the string and merging the parts you need. This can be combined with an endless loop to check the new string satisfies your condition: but think about when you need to break out of the loop.
Also, in your code:
v * (count - i)
String#* actually gives you count - i copies of v, concatenated together.

Ruby: Undefined method 'length' for nil:NilClass (NoMethodError)

I am attempting to write a program that takes in a string and outputs the longest word in that string. Now, I know that my code looks pretty hairy but I am pretty new to the Ruby language so please just bear with me. I don't understand any of the other explanations given regarding this issue. I am not looking for the answer. All I want is for a kind human being to please explain to me why my program halts at line 16 with the problem stated in the title of this question. Please and thank you!
# longest_word.rb
# A method that takes in a string and returns the longest word
# in the string. Assume that the string contains only
# letters and spaces. I have used the String 'split' method to
# aid me in my quest. Difficulty: easy.
def longest_word(sentence)
array = sentence.split(" ")
idx = 0
ordered_array = []
puts(array.length)
while idx <= array.length
if (array[idx].length) < (array[idx + 1].length)
short_word = array[idx]
ordered_array.push(short_word)
idx += 1
elsif array[idx].length > array[idx + 1].length
long_word = array[idx]
ordered_array.unshift(long_word)
idx += 1
else l_w = ordered_array[0]
return l_w
end
end
end
puts("\nTests for #longest_word")
puts(longest_word("hi hello goodbye"))
At some point in your while loop, you come to a state where idx is pointing to the last item in the array. At that point, asking for array[idx+1] returns nil, and NilClass does not have a method 'length'
The simple fix would be to change the while loop condition so that idx+1 is always within the array.
May I recommend a shorter solution.
words1= "This is a sentence." # The sentence
words2 = words1.split(/\W+/) # splits the words by via the space character
words3 = words2.sort_by {|x| x.length} #sort the array
words3[-1] #gets the last word
or
def longest_word(sentence)
sentence.split(/\W+/).sort_by {|x| x.length}[-1]
end

How do i print a string with repeated names followed by a number - Ruby? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
How do i print a name Ex. John1 and then print after John2, john3, john4, john5 and so one in an infinite number
I started using ruby today and I'm having some trouble figuring this out. I've searched some but can't find anything so how would I do this?
It's to mass produce accounts to the staff of a certain company and I found ruby to be the smartest to write it in and I will never use it again after this
Keep it simple.
puts (1..5).map { |n| "john#{n}" }
john1
john2
john3
john4
john5
The class Range includes the module Enumerable (as does the classes Array, Hash and others). By doing so, instances of Range (such as 1..5) gain the use of all of Enumerable's instance methods. One of Enumerable's instance methods is used here: Enumerable#map.
For printing a simple series like this:
n = 1
loop do
print 'john%d, ' % n
n += 1
end
That will never terminate, which makes it kind of silly. Maybe what you want is a bounded range:
list = (1..10).map do |n|
'john%d' % n
end.join(', ')
puts list
You can adjust the start and end values as necessary.
Perhaps use an enumerator here:
enum = Enumerator.new do |y|
i = 1
loop do
y << "John#{i}"
i += 1
end
end
enum.next #=> "John1"
enum.next #=> "John2"
enum.next #=> "John3"
Then use any one of the methods available to instances of Enumerator. Here we've used Enumerator#next to get the next "John" string.
One simple way is using a for loop. First declare an empty string variable that will hold our contents.
One important thing to consider is the index of the loop. If it's the last item, we do not want to add a separator like ", "
This is where the conditional comes into play. If the index is less than the last, we will add a comma and space, otherwise just the name.
Interpolation is done by wrapping a variable inside #{ and }
str = ""
for i in 1..5
str += i < 5 ? "john#{i}, " : "john#{i}"
end
Returns
"john1, john2, john3, john4, john5"

Reversing a Ruby String, without .reverse method

I am working on this coding challenge, and I have found that I am stuck. I thought it was possible to call the .string method on an argument that was passed in, but now I'm not sure. Everything I've found in the Ruby documentation suggests otherwise. I'd really like to figure this out without looking at the solution. Can someone help give me a push in the right direction?
# Write a method that will take a string as input, and return a new
# string with the same letters in reverse order.
# Don't use String's reverse method; that would be too simple.
# Difficulty: easy.
def reverse(string)
string_array = []
string.split()
string_array.push(string)
string_array.sort! { |x,y| y <=> x}
end
# These are tests to check that your code is working. After writing
# your solution, they should all print true.
puts(
'reverse("abc") == "cba": ' + (reverse("abc") == "cba").to_s
)
puts(
'reverse("a") == "a": ' + (reverse("a") == "a").to_s
)
puts(
'reverse("") == "": ' + (reverse("") == "").to_s
)
This is the simplest one line solution, for reversing a string without using #reverse, that I have come across -
"string".chars.reduce { |x, y| y + x } # => "gnirts"
Additionally, I have never heard of the #string method, I think you might try #to_s.
Easiest way to reverse a string
s = "chetan barawkar"
b = s.length - 1
while b >= 0
print s[b]
b=b-1
end
You need to stop the search for alternative or clever methods, such as altering things so you can .sort them. It is over-thinking the problem, or in some ways avoiding thinking about the core problem you have been asked to solve.
What this test is trying to get you you to do, is understand the internals of a String, and maybe get an appreciation of how String#reverse might be implemented using the most basic string operations.
One of the most basic String operations is to get a specific character from the string. You can get the first character by calling string[0], and in general you can get the nth character (zero-indexed) by calling string[n].
In addition you can combine or build longer strings by adding them together, e.g. if you had a="hell" and b="o", then c = a + b would store "hello" in the variable c.
Using this knowledge, find a way to loop through the original string and use that to build the reverse string, one character at a time. You may also need to look up how to get the length of a string (another basic string method, which you will find in any language's string library), and how to loop through numbers in sequence.
You're on the right track converting it to an array.
def reverse(str)
str.chars.sort_by.with_index { |_, i| -i }.join
end
Here is a solution I used to reverse a string without using .reverse method :
#string = "abcde"
#l = #string.length
#string_reversed = ""
i = #l-1
while i >=0 do
#string_reversed << #string[i]
i = i-1
end
return #string_reversed
Lol, I am going through the same challenge. It may not be the elegant solution, but it works and easy to understand:
puts("Write is a string that you want to print in reverse")
#taking a string from the user
string = gets.to_s #getting input and converting into string
def reverse(string)
i = 0
abc = [] # creating empty array
while i < string.length
abc.unshift(string[i]) #populating empty array in reverse
i = i + 1
end
return abc.join
end
puts ("In reverse: " + reverse(string))
Thought i'd contribute my rookie version.
def string_reverse(string)
new_array = []
formatted_string = string.chars
new_array << formatted_string.pop until formatted_string.empty?
new_array.join
end
def reverse_str(string)
# split a string to create an array
string_arr = string.split('')
result_arr = []
i = string_arr.length - 1
# run the loop in reverse
while i >=0
result_arr.push(string_arr[i])
i -= 1
end
# join the reverse array and return as a string
result_arr.join
end

Capitalizing words in an array, Ruby

I'm going through App Academy's Ruby Prep questions, and I want to know why this solution works. It appears that the words array is never altered and yet the method works. Is this a glitch in the matrix, or is it right under my nose?
def capitalize_words(string)
words = string.split(" ")
idx = 0
while idx < words.length
word = words[idx]
word[0] = word[0].upcase
idx += 1
end
return words.join(" ")
end
The method works because word contains a reference to the array position. So when you assign:
word = words[idx]
You're just using word as a shorthand to operate on that array element, which gets modified by:
word[0] = word[0].upcase
--
Also, if you'd like to come back to this answer after learning some Ruby, here's a simplified version of the method:
def capitalize_words(string)
string.split.map(&:capitalize).join(' ')
end
String#[]= is a mutating operation. To illustrate using a concise, contained excerpt from your code:
word = "foo"
word[0] = word[0].upcase # <-- verbatim from your code
word #=> "Foo"
word is still the same exact object contained in the array words (arrays simply contain references to objects, not the data within them), but it has been mutated in-place. It’s generally best to avoid mutations whenever possible as it makes it non-obvious what is happening (as you can see).
Your code could also be more concisely written using map & capitalize (and without any mutations):
string.split(' ').map(&:capitalize).join(' ')
word = word[idx] creates a copy of your data. It will then modify that copy instead of the words in the original array.
Simple solution would be:
def capitalize_words(string)
words = string.split(" ")
idx = 0
while idx < words.length
words[idx][0] = words[idx][0].upcase
idx += 1
end
return words.join(" ")
end

Resources