Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reverse a string in Ruby

Tags:

ruby

How do you reverse a string in Ruby? I know about string#reverse. I'm interested in understanding how to write it in pure Ruby, preferably an in-place solution.

like image 599
rubynoob Avatar asked Jun 16 '10 23:06

rubynoob


People also ask

How do you reverse a string in Ruby without reverse?

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.

How do you reverse an integer in Ruby?

I was trying to reverse the digits of an integer: 123456 => 654321 , and the best solution that I could come up with was 123456. to_s. reverse. to_i .

What is chomp in Ruby?

chomp! is a String class method in Ruby which is used to returns new String with the given record separator removed from the end of str (if present). chomp method will also removes carriage return characters (that is it will remove \n, \r, and \r\n) if $/ has not been changed from the default Ruby record separator, t.


2 Answers

There's already an inplace reverse method, called "reverse!":

$ a = "abc" $ a.reverse! $ puts a cba 

If you want to do this manually try this (but it will probably not be multibyte-safe, eg UTF-8), and it will be slower:

class String   def reverse_inplace!     half_length = self.length / 2     half_length.times {|i| self[i], self[-i-1] = self[-i-1], self[i] }     self   end end 

This swaps every byte from the beginning with every byte from the end until both indexes meet at the center:

$ a = "abcd" $ a.reverse_inplace! $ puts a dcba 
like image 181
hurikhan77 Avatar answered Sep 17 '22 21:09

hurikhan77


Just for discussion, with that many alternates, it is good to see if there are major differences in speed/efficiency. I cleaned up the code a bit as the code showing output was repeatedly reversing the outputs.

# encoding: utf-8  require "benchmark"  reverse_proc = Proc.new { |reverse_me| reverse_me.chars.inject([]){|r,c| r.unshift c}.join }  class String   def reverse # !> method redefined; discarding old reverse     each_char.to_a.reverse.join   end    def reverse! # !> method redefined; discarding old reverse!     replace reverse   end    def reverse_inplace!     half_length = self.length / 2     half_length.times {|i| self[i], self[-i-1] = self[-i-1], self[i] }   end  end  def reverse(a)   (0...(a.length/2)).each {|i| a[i], a[a.length-i-1]=a[a.length-i-1], a[i]}   return a end  def reverse_string(string) # method reverse_string with parameter 'string'   loop = string.length       # int loop is equal to the string's length   word = ''                  # this is what we will use to output the reversed word   while loop > 0             # while loop is greater than 0, subtract loop by 1 and add the string's index of loop to 'word'     loop -= 1                  # subtract 1 from loop     word += string[loop]       # add the index with the int loop to word   end                        # end while loop   return word                # return the reversed word end                        # end the method  lorum = <<EOT Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent quis magna eu lacus pulvinar vestibulum ut ac ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse et pretium orci. Phasellus congue iaculis sollicitudin. Morbi in sapien mi, eget faucibus ipsum. Praesent pulvinar nibh vitae sapien congue scelerisque. Aliquam sed aliquet velit. Praesent vulputate facilisis dolor id ultricies. Phasellus ipsum justo, eleifend vel pretium nec, pulvinar a justo. Phasellus erat velit, porta sit amet molestie non, pellentesque a urna. Etiam at arcu lorem, non gravida leo. Suspendisse eu leo nibh. Mauris ut diam eu lorem fringilla commodo. Aliquam at augue velit, id viverra nunc. EOT 

And the results:

RUBY_VERSION # => "1.9.2"  name = "Marc-André"; reverse_proc.call(name) # => "érdnA-craM" name = "Marc-André"; name.reverse! # => "érdnA-craM" name = "Marc-André"; name.chars.inject([]){|s, c| s.unshift(c)}.join # => "érdnA-craM" name = "Marc-André"; name.reverse_inplace!; name # => "érdnA-craM" name = "Marc-André"; reverse(name) # => "érdnA-craM" name = "Marc-André"; reverse_string(name) # => "érdnA-craM"  n = 5_000 Benchmark.bm(7) do |x|   x.report("1:") { n.times do; reverse_proc.call(lorum); end }   x.report("2:") { n.times do; lorum.reverse!; end }   x.report("3:") { n.times do; lorum.chars.inject([]){|s, c| s.unshift(c)}.join; end }   x.report("4:") { n.times do; lorum.reverse_inplace!; end }   x.report("5:") { n.times do; reverse(lorum); end }   x.report("6:") { n.times do; reverse_string(lorum); end } end  # >>              user     system      total        real # >> 1:       4.540000   0.000000   4.540000 (  4.539138) # >> 2:       2.080000   0.010000   2.090000 (  2.084456) # >> 3:       4.530000   0.010000   4.540000 (  4.532124) # >> 4:       7.010000   0.000000   7.010000 (  7.015833) # >> 5:       5.660000   0.010000   5.670000 (  5.665812) # >> 6:       3.990000   0.030000   4.020000 (  4.021468) 

It's interesting to me that the "C" version ("reverse_string()") is the fastest pure-Ruby version. #2 ("reverse!") is fastest but it's taking advantage of the [].reverse, which is in C.

  • Edit by Marc-André Lafortune *

Adding an extra test case (7):

def alt_reverse(string)   word = ""   chars = string.each_char.to_a   chars.size.times{word << chars.pop}   word end 

If the string is longer (lorum *= 10, n/=10), we can see that the difference widens because some functions are in O(n^2) while others (mine :-) are O(n):

             user     system      total        real 1:      10.500000   0.030000  10.530000 ( 10.524751) 2:       0.960000   0.000000   0.960000 (  0.954972) 3:      10.630000   0.080000  10.710000 ( 10.721388) 4:       6.210000   0.060000   6.270000 (  6.277207) 5:       4.210000   0.070000   4.280000 (  4.268857) 6:      10.470000   3.540000  14.010000 ( 15.012420) 7:       1.600000   0.010000   1.610000 (  1.601219) 
like image 22
the Tin Man Avatar answered Sep 18 '22 21:09

the Tin Man