Number of repeats - ruby

Write a method that takes in a string and returns the number of letters that appear more than once in the string. You may assume the string contains only lowercase letters. Count the number of letters that repeat, not the number of times they repeat in the string.
I implemented methods and test cases as:
def num_repeats(string)
count = 0
dix = 0
new = ""
while dix < string.length
letter = string[dix]
if !(new.include?(letter))
new = new + "letter"
else
break
end
dix2 = dix + 1
while dix2 < string.length
if letter == string[dix2]
count +=1
break
end
dix2 +=1
end
dix += 1
end
puts(count.to_s)
return count
end
# These are tests to check that your code is working. After writing
# your solution, they should all print true.
puts('num_repeats("abdbc") == 1: ' + (num_repeats('abdbc') == 1).to_s)
# one character is repeated
puts('num_repeats("aaa") == 1: ' + (num_repeats('aaa') == 1).to_s)
puts('num_repeats("abab") == 2: ' + (num_repeats('abab') == 2).to_s)
puts('num_repeats("cadac") == 2: ' + (num_repeats('cadac') == 2).to_s)
puts('num_repeats("abcde") == 0: ' + (num_repeats('abcde') == 0).to_s)
Test results:
1
num_repeats("abdbc") == 1: true
2
num_repeats("aaa") == 1: false
2
num_repeats("abab") == 2: true
2
num_repeats("cadac") == 2: true
0
num_repeats("abcde") == 0: true
For the second test that returned false, what was wrong with my code?

You are appending "letter", rather than the letter variable to new on line 8.
if !(new.include?(letter))
new = new + "letter"
else
#...
end
becomes:
unless new.include?(letter)
new = new + letter
else
#...
end

Related

Longest Run Program In Ruby

I have a school assignment where i have to find the longest run of adjacent equal characters in a given string with Ruby. My program works fine without the last loop, but once i added it gave me the error:
(repl):47: syntax error, unexpected keyword_end
(repl):53: syntax error, unexpected end-of-input, expecting keyword_end
puts longestRun
^
Here is my Code
puts 'What is your string?'
givenString = gets.chomp
def maxBlock(str)
maxRun = 0
currentRun = 1
characterCounter = 1
if str.length == 0
maxRun = 0
#If no input, longest run is zero
elsif str.length == 1
maxRun = 1
#If string is one character, longest run is 1
elsif str.length == 2 and str[characterCounter] != str[characterCounter + 1]
maxRun = 1
#if string is two chars and they do not equal, longest run is 1
elsif str.length == 3 and str[0] != str[1] and str[1] != str[2]
maxRun = 1
#if string is three chars and they do not equal, longest run is 1
else
str.each_char do|st|
#Go through each char, compare it to the next, find longest run
if st == str[characterCounter]
currentRun++
if currentRun > maxRun
maxRun = currentRun
end
else
currentRun = 1
end
characterCounter++
end
end
end
longestRun = maxBlock(givenString)
puts longestRun
EDIT: I am a highschool student, and only have a base knowledge of programming.
EDIT: I just made a few stupid mistakes. I appreciate everyone's help. Here is my working program without the use of anything too complicated.
puts 'What is your string?'
givenString = gets.chomp
def maxBlock(str)
maxRun = 0
currentRun = 1
characterCounter = 0
if str.length == 0
maxRun = 0
#If no input, longest run is zero
elsif str.length == 1
maxRun = 1
#If string is one character, longest run is 1
elsif str.length == 2 and str[characterCounter] != str[characterCounter + 1]
maxRun = 1
#if string is two chars and they do not equal, longest run is 1
elsif str.length == 3 and str[0] != str[1] and str[1] != str[2]
maxRun = 1
#if string is three chars and they do not equal, longest run is 1
else
characterCounter += 1
str.each_char do|st|
#Go through each char, compare it to the next, find longest run
if st == str[characterCounter]
currentRun += 1
if currentRun > maxRun
maxRun = currentRun
end
else
currentRun = 1
end
characterCounter += 1
end
end
return maxRun
end
longestRun = maxBlock(givenString)
puts longestRun
String Scans and Sorting
There are algorithms for this, but Ruby offers some nice shortcuts. For example:
def longest_string str
str.scan(/((\p{Alnum})\2+)/).collect { |grp1, grp2| grp1 }.sort_by(&:size).last
end
longest_string 'foo baaar quuuux'
#=> "uuuu"
This basically just captures all runs of repeated characters, sorts the captured substrings by length, and then returns the last element of the length-sorted array.
Secondary Sorting
If you want to do a secondary sort, such as first by length and then by alphabetical order, you could replace Enumerable#sort_by with the block form of Enumerable#sort. For example:
def longest_string str
str.scan(/((\p{Alnum})\2+)/).
collect { |grp1, grp2| grp1 }.
sort {|a, b| [a.size, a] <=> [b.size, b] }.
last
end
longest_string 'foo quux baar'
#=> "uu"
This is one way you could do it.
str = "111 wwwwwwwwaabbbbbbbbbbb$$$$****"
r = /
(.) # Match any character in capture group 1
\1* # Match the contents of capture group 1 zero or more times
/x # Free-spacing regex definition mode
str.gsub(r).max_by(&:size)
#=> "bbbbbbbbbbb"
I used the form of String#gsub without a second argument or block, as that returns an enumerator that generates the strings matched by the regex. I then chained that enumerator to the method Enumerable#max_by to find the longest string of consecutive characters. In other words, I used gsub merely to generate matches rather than to perform substitutions.
One could of course write str.gsub(/(.)\1*/).max_by(&:size).
Here is a simplified version that should work in all cases:
puts 'What is your string?'
given_string = gets.chomp
def max_block(str)
max_run = 0
current_run = 1
str.each_char.with_index do |st, idx|
if st == str[idx + 1]
current_run += 1
else
current_run = 1
end
max_run = current_run if current_run > max_run
end
max_run
end
longest_run = max_block(given_string)
puts longest_run
You were on the right track but Ruby can make things a lot easier for you. Notice how with_index gets rid of a lot of the complexity. Iterators, oh yeah.
I also changed your method name and variables to camel_case.
Happy coding!

Counting X's and O's in a string in Ruby

I'm not sure why my code is not working, I think my logic is right?
Have the function ExOh(str) take the str parameter being passed and return the string true if there is an equal number of x's and o's, otherwise return the string false. Only these two letters will be entered in the string, no punctuation or numbers. For example: if str is "xooxxxxooxo" then the output should return false because there are 6 x's and 5 o's.
ExOh(str)
i = 0
length = str.length
count_x = 0
count_o = 0
while i < length
if str[i] == "x"
count_x += 1
elsif str[i] == "o"
count_o += 1
end
i+=1
end
if (count_o == count_x)
true
elsif (count_o != count_x)
false
end
end
The problem with your code is the function declaration. Use def ExOh(str) at the start. It may help if you indented also.
def ExOh(str)
i = 0
length = str.length
count_x = 0
count_o = 0
while i < length
if str[i] == "x"
count_x += 1
elsif str[i] == "o"
count_o += 1
end
i+=1
end
if (count_o == count_x)
true
elsif (count_o != count_x)
false
end
end
By the way, a simpler solution using the standard library #count https://ruby-doc.org/core-2.2.0/String.html#method-i-count
def ExOh(str)
str.count('x') == str.count('o')
end

why does this ruby code not return anything?

I'm trying to take a number and return a string with dashes around any odd numbers. Also, the string should not begin or end with a dash.
I've written the following but it does not return anything:
def dasherize_number(num)
string = num.to_s
i = 0
while i<string.length
if (string[i].to_i % 2) != 0
string[i] = '-' + string[i] + '-'
end
i += 1
end
if string[0] == '-'
string.pop(1)
end
if (string.length - 1) == '-'
string.pop(1)
end
string
end
It appears to be looping infinitely if I understand correctly; the console shows no output and doesn't allow me to do anything else unless I refresh. I've reviewed the code by each character, but I can't figure where it goes wrong.
There were a lot of logical issues in your code.
here's something that might just work for you
def dasherize_number(num)
string = num.to_s
str_len = string.length
i = 0
while i < str_len
next if string[i] == '-'
if (string[i].to_i % 2) != 0
string[i] = '-' + string[i] + '-'
str_len = string.length
i += 3
else
i += 1
end
end
if string[0] == '-'
string = string[1..-1]
end
if (string[string.length - 1]) == '-'
string = string[0..-2]
end
string.gsub('--', '-')
end
Explaination
Firstly, you had this condition in your while loop i < string.length
Which wouldn't work, because the length of the string keeps changing. So i've used a variable to store the value and update the variable if the string is updated.
If the string is updated, we can be sure that we can skip the next two indexes.
eg: number inputed -> 122
then after first iteration the string would be -1-22
so we don't want to run the same condition for the next index because, that would be 1 again, hence the infinite loop. (Hope you get the idea)
pop wouldn't work on string, just because we can access characters using indexes like for arrays, we can't use pop for strings.
To make sure there are no consecutive dashes, i've used gsub to replace them with single dash.
The problem seems to be in this part of the code:
while i<string.length
if (string[i].to_i % 2) != 0
string[i] = '-' + string[i] + '-'
end
i += 1
end
If your string contains odd number it increases its length by 2 more chars (2x-), but incrementing it by 1 (i+=1).
Assign initial string length to a var and check its length in the while loop.
string_length = string.length
while i < string_length
if ((string[i].to_i % 2) != 0)
string[i] = '-' + string[i] + '-'
end
i += 1
end

Undefined methods length and next! for nil:NilClass

I have this code:
def encrypt(x)
index = 0
alphabet = "abcdefghijklmnopqrstuvwxyz"
while index < x.length
letter = x[index]
if letter == ' '
print ' '
index += 1
elsif letter == "z"
print "a"
index += 1
else
letter = alphabet[letter].next!
index += 1
print letter
end
end
end
def decrypt(x)
number = 0
alphabet = "abcdefghijklmnopqrstuvwxyz"
while number < x.length
green = x[number]
if green == ' '
print ' '
number += 1
else
red = alphabet.index(green)
red = red.to_i
blue = red - 1
yellow = alphabet[blue]
print yellow
number += 1
end
end
end
If I add a capital letter such as in:
encrypt("Dhd d hd h")
it returns:
undefined method `next!' for nil:NilClass
(repl):13:in `encrypt'
(repl):39:in `initialize'
or if I try to use both methods:
encrypt(decrypt("Dhddhdh"))
it returns
undefined method `length' for nil:NilClass
(repl):4:in `encrypt'
(repl):39:in `initialize'
I thought it was due to having a space in the argument, and added an if/ else for that, but no luck. Can someone point me in the right direction?
On both cases your alphabeth should include lowercase and downcase caracteres:
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Other problem with your code is, instead printing the caracteres, I suggest you to return a value:
def encrypt(x)
index = 0
encrypted = ""
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
while index < x.length
letter = x[index]
if letter == ' '
encrypted << ' '
elsif letter == "z"
encrypted << "a"
elsif letter == "Z"
encrypted << "A"
else
letter = alphabet[letter].next!
encrypted << letter
end
index += 1
end
encrypted
end
Decrypt method:
def decrypt(x)
index = 0
decrypted = ""
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
while index < x.length
letter = x[index]
if letter == ' '
decrypted << ' '
elsif letter == "A"
decrypted << "Z"
else
blue = alphabet.index(letter) - 1
decrypted << alphabet[blue]
end
index += 1
end
decrypted
end

Code doesn't work in coderbytes but it works in Cloud9

In Cloud9 I use the following code and it works.
def LongestWord(sen)
i = 0
cha ="&#%*^$!~(){}|?<>"
new = ""
while i < sen.length
i2 = 0
ch = false
while i2 < cha.length
if sen[i] == cha[i2]
ch = true
end
i2 += 1
end
if ch == false
new += sen[i].to_s
end
i += 1
end
words = new.split(" ")
longest = ""
idx = 0
count = 0
while idx < words.length
word = words[idx]
if word.length > count
longest = word
count = word.length
end
idx += 1
end
# code goes here
return longest
end
# keep this function call here
# to see how to enter arguments in Ruby scroll down
LongestWord("beautifull word")
In Codebytes in the exercise "Longest Word" you have to use the same STDIN in the arguments. It is the same code but changing the argument but it doesn't work:
def LongestWord(sen)
i = 0
cha ="&#%*^$!~(){}|?<>"
new = ""
while i < sen.length
i2 = 0
ch = false
while i2 < cha.length
if sen[i] == cha[i2]
ch = true
end
i2 += 1
end
if ch == false
new += sen[i].to_s
end
i += 1
end
words = new.split(" ")
longest = ""
idx = 0
count = 0
while idx < words.length
word = words[idx]
if word.length > count
longest = word
count = word.length
end
idx += 1
end
# code goes here
return longest
end
# keep this function call here
# to see how to enter arguments in Ruby scroll down
LongestWord(STDIN.gets)
I think may be something is creating some kind of conflict with the browser. The output shows a lot of numbers. Can some one help me testing the code?. Any feedback is appreciated, thanks!
Coderbyte is running your code on an old version of Ruby - Ruby 1.8.7
In this version of Ruby, using an index into a string like sen[i] doesn't return the character at i, it returns the numeric ASCII value of that character instead. That's where the numbers are coming from.
To get the code to work on Ruby 1.8.7 you can replace some_string[i] with some_string[i, 1] - this variation returns the substring of length 1 starting at i so is the same as the behaviour of some_string[i] in more recent Ruby versions. See the docs here for more details.

Resources