在Ruby中反转一个字符串

时间:2010-06-16 23:43:32

标签: ruby

如何在Ruby中反转字符串?我知道字符串#verse。我有兴趣了解如何用纯Ruby编写它,最好是就地解决方案。

22 个答案:

答案 0 :(得分:39)

已经存在一种称为“反向!”的原位反向方法:

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

如果你想手动试试这个(但它可能不是多字节安全的,例如UTF-8),它会慢一点:

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

这将从开头的每个字节开始交换每个字节,直到两个索引在中心相交:

$ a = "abcd"
$ a.reverse_inplace!
$ puts a
dcba

答案 1 :(得分:12)

只是为了讨论,有很多替补,很高兴看到速度/效率有很大差异。我稍微清理了代码,因为显示输出的代码反复反转输出。

# 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

结果:

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)

有趣的是,“C”版本(“reverse_string()”)是最快的纯Ruby版本。 #2(“反向!”)是最快的,但它正在利用{C}中的[].reverse

  • 由Marc-AndréLafortune编辑*

添加额外的测试用例(7):

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

如果字符串更长(lorum *= 10, n/=10),我们可以看到差异变宽,因为某些函数在O(n ^ 2)中,而其他函数(我的:-)是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)

答案 2 :(得分:8)

这是使用inject和unshift执行此操作的一种方法:

"Hello world".chars.inject([]) { |s, c| s.unshift(c) }.join

答案 3 :(得分:7)

内置reverse的Ruby等价物看起来像:

# encoding: utf-8

class String
  def reverse
    each_char.to_a.reverse.join
  end

  def reverse!
    replace reverse
  end
end

str = "Marc-André"
str.reverse!
str # => "érdnA-craM"
str.reverse # => "Marc-André"

注意:这假定为Ruby 1.9,或者require "backports",并为UTF-8设置$KCODE

对于不涉及reverse的解决方案,可以这样做:

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

注意:使用[]访问单个字母的任何解决方案都是O(n^2)的顺序;要访问第1000个字母,Ruby必须逐个检查第一个999以检查多字节字符。因此,对each_char中的解决方案使用像O(n)这样的迭代器非常重要。

要避免的另一件事是建立增加长度的中间值;在+=中使用<<代替alt_reverse也可以使解O(n^2)代替O(n)

使用unshift构建数组也会生成解决方案O(n^2),因为它意味着每次执行unshift时重新复制一个索引更高的所有现有元素。

答案 4 :(得分:5)

str = "something"
reverse = ""
str.length.times do |i|
  reverse.insert(i, str[-1-i].chr)
end

答案 5 :(得分:4)

"abcde".chars.reduce{|s,c| c + s }          # => "edcba"

答案 6 :(得分:3)

使用

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.

答案 7 :(得分:2)

下面描述的解决方案。没有必要超出数组大小的一半:

module V2
end

答案 8 :(得分:1)

难以阅读单行,

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

答案 9 :(得分:1)

另外,使用Procs ...

Proc.new {|reverse_me| reverse_me.chars.inject([]){|r,c| r.unshift c}.join}.call("The house is blue")

=> "eulb si esuoh ehT"

Proc.new在这里会很方便,因为你可以嵌套你的反转算法(并且仍然保持一条线)。例如,如果您需要在已经反转的句子中反转每个单词,这将非常方便:

# Define your reversing algorithm
reverser = Proc.new{|rev_me| rev_me.chars.inject([]){r,c| r.unshift c}.join}

# Run it twice - first on the entire sentence, then on each word
reverser.call("The house is blue").split.map {|w| reverser.call(w)}.join(' ')

=> "blue is house The"

答案 10 :(得分:1)

考虑一下Rubinius如何实现该方法 - 它们在Ruby本身中实现了大部分核心库,如果在Ruby中实现String#reverseString#reverse!,我不会感到惊讶。

答案 11 :(得分:1)

这是一个对我来说最有意义的解决方案作为红宝石初学者

def reverse(string)
  reversed_string = ''

  i = 0
  while i < string.length
    reversed_string = string[i] + reversed_string
    i += 1
  end

  reversed_string
end

p reverse("helter skelter")

答案 12 :(得分:1)

def palindrome(string)

  s = string.gsub(/\W+/,'').downcase

  t = s.chars.inject([]){|a,b| a.unshift(b)}.join

  return true if(s == t)

  false

end

答案 13 :(得分:1)

def reverse(string)
  result = ""
  idx = string.length - 1
  while idx >= 0
  result << string [idx]
  idx = idx - 1
 end

 result

end 

答案 14 :(得分:0)

n / 2复杂度的简单经典方式

str = "Hello World!";
puts str;

for i in 0..(str.length/2).to_i
  mid = (str.length-1-i);
  temp = str[i];
  str[i] = str[aa];
  str[aa] = temp;
end

puts str;

答案 15 :(得分:0)

这是一个简单的替代方案,它首先将字符串分解为数组,计算长度并减去一个(因为ruby的索引规则从0开始的数组),创建一个空变量,然后在键上运行迭代数组,同时将数组长度减去当前数组索引的值附加到创建的空变量,当它到达第0个(对不起我的法语)值时,它会停止。希望这会有所帮助。

class String
   def rString
       arr = self.split("")
       len = arr.count - 1
       final = ""
       arr.each_index do |i|
           final += arr[len - i]
       end
       final
  end
end

答案 16 :(得分:0)

HttpContext.Current.Request.Headers["Origin"].ToString()

答案 17 :(得分:0)

如果你有句“最伟大的胜利就是那个”并且你想拥有“那是胜利最大的”你应该使用这种方法

def solution(sentance)
  sentance.split.reverse.join(" ")
end

solution("The greatest victory is that")

答案 18 :(得分:0)

def reverse(string)
reversed_string = ""

idx = 0
while idx < string.length
reversed_string = string[idx] + reversed_string
idx += 1
end

return reversed_string
end

答案 19 :(得分:0)

我相信这也会起作用

def reverse(str)
  string = ''
   (0..str.size-1).each do |i|
    string << str[str.size - 1 - i]
   end
  string
end

答案 20 :(得分:0)

在Ruby中:

name = "Hello World"; reverse_proc.call(name) 

name = "Hello World"; name.reverse! 

name = "Hello World"; name.chars.inject([]){|s, c| s.unshift(c)}.join 

name = "Hello World"; name.reverse_inplace!; 

name = "Hello World"; reverse(name) 

name = "Hello World"; reverse_string(name) 

答案 21 :(得分:0)

这是使用xor按位运算的替代方法:

class String

  def xor_reverse
    len = self.length - 1
    count = 0

    while (count < len)
      self[count] ^= self[len]
      self[len] ^= self[count]
      self[count] ^= self[len]

      count += 1
      len -= 1
    end

  self
end

"foobar".xor_reverse
=> raboof