Method to reverse string only if it has less than four letters - ruby

I need to write a ruby method that reverses a string only if it has less than four characters.
# Write a method that reverses
# a string ONLY if it's shorter than
# 4 letters.
# Otherwise, the string is
# returned as-is.
# (Hint: strings have
# a built-in .length method!)
# conditional_reverse("yo")
# => "oy"
# conditional_reverse("hello")
# => "hello"
Here is the code I came up with.
def conditional_reverse(string)
good = string.length
if good < 4
puts string.reverse
else
puts string
end
puts conditional_reverse("cat")
end
When I run it in repl I get the following response
:conditional_reverse
I have no idea what i'm doing wrong.

just put puts conditional_reverse("cat") out side our def
def conditional_reverse(string)
good = string.length
if good < 4
puts string.reverse
else
puts string
end
end
conditional_reverse("cat")

You are callind your method in its definition. Avoid it if you are not writing a recursive method.
def conditional_reverse(s)
s.length < 4 ? s.reverse : s
end

The answer provided by #Ursus is perfect, but in case you want to go with your way the change you have to do is this;
def conditional_reverse(string)
good = string.length
if good < 4
puts string.reverse
else
puts string
end
end
puts conditional_reverse("cat")

What the others said, plus...
You get that response from irb because in recent versions of Ruby, a method definition returns the method name as a symbol.
Also, your problem specifies that the string should be reversed, not that the string should be output reversed; so you should remove the puts calls and just manipulate the string.
For the benefit of your readers, I recommend being specific with your names. good = string.length could be changed to needs_reversing = string.length < 4, for example.

Related

Does anyone see the error in this simple Ruby function?

This function is supposed to take a string and return the characters in reverse order.
def reverse(string)
reversedString = "";
i = string.length - 1
while i >= 0
reversedString = reversedString + string[i]
i -= 1
end
puts reversedString
end
however all the tests return false:
puts(
'reverse("abc") == "cba": ' + (reverse("abc") == "cba").to_s
)
puts(
'reverse("a") == "a": ' + (reverse("a") == "a").to_s
)
puts(
'reverse("") == "": ' + (reverse("") == "").to_s
)
Does anyone see what the problem is?
Try to use the default String class reverse method like this:
"Hello World".reverse
"Hello World".reverse!
Check Ruby's String class API at https://ruby-doc.org/core-2.4.0/String.html
If you want to make your custom method, you could use a map like this:
string = String.new
"Hello World".chars.each { | c | string.prepend c }
The problem is your function isn't returning its result, it's printing it. It needs to return reversedString.
As a rule of thumb, functions should return their result. Another function should format and print it.
def reverse(string)
reversedString = "";
i = string.length - 1
while i >= 0
reversedString = reversedString + string[i]
i -= 1
end
return reversedString
end
Note: This was probably an exercise, but Ruby already has String#reverse.
It's good that you're writing tests, but the way you're writing them it's hard to tell what went wrong. Look into a Ruby testing framework like MiniTest.
require "minitest/autorun"
class TestReverse < Minitest::Test
def test_reverse
assert_equal "cba", reverse("abc")
assert_equal "a", reverse("a")
assert_equal "", reverse("")
end
end
That would have told you that your function is returning nil.
1) Failure:
TestReverse#test_reverse [test.rb:16]:
Expected: "cba"
Actual: nil
To make this more Ruby-like yet avoid using the built-in String#reverse method you'd do this:
def reverse(string)
string.chars.reverse.join('')
end
Remember that in Ruby the result of the last operation is automatically the return value of the method. In your case the last operation is puts which always returns nil, eating your value. You want to pass it through.
Try to design methods with a simple mandate, that is, this function should focus on doing one job and one job only: reversing a string. Displaying it is beyond that mandate, so that's a job for another method, like perhaps the caller.
To avoid calling any sort of reverse method at all:
def reverse(string)
result = ''
length = string.length
length.times do |i|
result << string[length - 1 - i]
end
result
end
You can often avoid for almost completely and while frequently if you use things like times or ranges (0..n) to iterate over.
puts prints and returns nil, so the whole method returns nil. If, for debugging reasons , you want to inspect what your method is returning, use p which returns it's argument (reversedString in this case).
def reverse(string)
reversedString = ""
i = string.length - 1
while i >= 0
reversedString = reversedString + string[i]
i -= 1
end
p reversedString # !!!
end
And all 3 tests return true
If I was going to do this, I'd probably take advantage of an array:
ary = 'foo bar baz'.chars
reversed_ary = []
ary.size.times do
reversed_ary << ary.pop
end
reversed_ary.join # => "zab rab oof"
pop removes the last character from the array and returns it, so basically it's walking backwards through ary, nibbling at the end and pushing each character onto the end of reversed_ary, effectively reversing the array.
Alternately it could be done using a string:
ary = 'foo bar baz'.chars
reversed_str = ''
ary.size.times do
reversed_str << ary.pop
end
reversed_str # => "zab rab oof"
or:
reversed_str += ary.pop
I just saw that #tadman did a similar thing with the string. His would run more quickly but this is more readable, at least to my eyes.

Creating a modified capitalize method in Ruby from scratch

I am learning methods in Ruby and thought that the best way to learn them was to create a method that already exists. However, there are two problems that I am running in to:
I do not know what the capitalize method looks like
My solution (it does more than the original method does) seems like it can be refactored into something more elegant.
This is what I have come up with:
# method that capitalizes a word
def new_capitalize(string)
if string[0].downcase == "m" && string[1].downcase == "c"
puts "#{string[0].upcase}#{string[1].downcase}#{string[2].upcase}#{string[3..-1].downcase}"
else
puts "#{string[0].upcase}#{string[1..-1].downcase}"
end
end
name1 = "ryan"
name2 = "jane"
new_capitalize(name1) # prints "Ryan"
new_capitalize(name2) # prints "Jane"
str = "mCnealy"
puts str.capitalize
# prints "Mcnealy"
new_capitalize(str)
# prints "McNealy"
It seems as if the first part of my if statement could be made much more efficient. It does not need to be even close to my solution as long as it prints the second capital if the name begins with "mc"
Also, if someone could point me to where the built in capitalize method's code could be found that would be great too!
Thank you in advance!
Alright, how about:
module NameRules
refine String do
def capitalize
if self[0..1].downcase == 'mc'
"Mc#{self[2..-1].capitalize}"
else
super
end
end
end
end
Then to use it:
class ThingWithNames
using NameRules
def self.test(string)
string.capitalize
end
end
ThingWithNames.test('mclemon') # => "McLemon"
ThingWithNames.test('lemon') # => "Lemon"
If we were starting from scratch and not using the C implemented code:
module NameRules
refine String do
def capitalize
if self[0..1].downcase == 'mc'
"Mc#{self[2..-1].capitalize}"
else
new_string = self.downcase
new_string[0] = new_string[0].upcase
new_string
end
end
end
end
Reference materials:
String#capitalize source
A really good presentation on refinements
First, in my opinion, doing anything other than capitalizing the first letter of the string should be a different method or an optional arg you pass. Second, if you are trying to mimic the core lib behavior than you could monkey-patch String.
class String
def capitalize
self[0].upcase << self[1..-1].downcase
end
end
The closest to an official ruby implementation is probably Rubinius
https://github.com/rubinius/rubinius/blob/377d5c958bc8239514fb98701b75859c6b51b9d4/core/string.rb#L332

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

Truncate string when it is too long

I have two strings:
short_string = "hello world"
long_string = "this is a very long long long .... string" # suppose more than 10000 chars
I want to change the default behavior of print to:
puts short_string
# => "hello world"
puts long_string
# => "this is a very long long....."
The long_string is only partially printed. I tried to change String#to_s, but it didn't work. Does anyone know how to do it like this?
updated
Actually i wanna it works smoothly, that means the following cases also work fine:
> puts very_long_str
> puts [very_long_str]
> puts {:a => very_long_str}
So i think the behavior belongs to String.
Thanks all anyway.
First of all, you need a method to truncate a string, either something like:
def truncate(string, max)
string.length > max ? "#{string[0...max]}..." : string
end
Or by extending String: (it's not recommended to alter core classes, though)
class String
def truncate(max)
length > max ? "#{self[0...max]}..." : self
end
end
Now you can call truncate when printing the string:
puts "short string".truncate
#=> short string
puts "a very, very, very, very long string".truncate
#=> a very, very, very, ...
Or you could just define your own puts:
def puts(string)
super(string.truncate(20))
end
puts "short string"
#=> short string
puts "a very, very, very, very long string"
#=> a very, very, very, ...
Note that Kernel#puts takes a variable number of arguments, you might want to change your puts method accordingly.
This is how Ruby on Rails does it in their String#truncate method as a monkey-patch:
class String
def truncate(truncate_at, options = {})
return dup unless length > truncate_at
options[:omission] ||= '...'
length_with_room_for_omission = truncate_at - options[:omission].length
stop = if options[:separator]
rindex(options[:separator], length_with_room_for_omission) ||
length_with_room_for_omission
else
length_with_room_for_omission
end
"#{self[0...stop]}#{options[:omission]}"
end
end
Then you can use it like this
'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
# => "And they f... (continued)"
You can write a wrapper around puts that handles truncation for you:
def pleasant(string, length = 32)
raise 'Pleasant: Length should be greater than 3' unless length > 3
truncated_string = string.to_s
if truncated_string.length > length
truncated_string = truncated_string[0...(length - 3)]
truncated_string += '...'
end
puts truncated_string
truncated_string
end
Truncate naturally
I want to propose a solution that truncates naturally. I fell in love with the String#truncate method offered by Ruby on Rails. It was already mentioned by #Oto Brglez above. Unfortunately I couldn't rewrite it for pure ruby. So I wrote this function.
def truncate(content, max)
if content.length > max
truncated = ""
collector = ""
content = content.split(" ")
content.each do |word|
word = word + " "
collector << word
truncated << word if collector.length < max
end
truncated = truncated.strip.chomp(",").concat("...")
else
truncated = content
end
return truncated
end
Example
Test: I am a sample phrase to show the result of this function.
NOT: I am a sample phrase to show the result of th...
BUT: I am a sample phrase to show the result of...
Note: I'm open for improvements because I'm convinced that there is a shorter solution possible.
You can just use this syntax:
"mystring"[0..MAX_LENGTH]
[5] pry(main)> "hello world"[0..10]
=> "hello world"
[6] pry(main)> "hello world why"[0..10]
=> "hello world"
[7] pry(main)> "hello"[0..10]
=> "hello"
There's no need to check if it actually exceed the maximum length.

Use of yield and return in Ruby

Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.

Resources