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.
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.
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 .
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.
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
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With