Подтвердить что ты не робот

Обратить строку в Ruby

Как изменить строку в Ruby? Я знаю о строке # reverse. Мне интересно понять, как писать его в чистом Ruby, желательно на месте решения.

4b9b3361

Ответ 1

Там уже есть обратный метод inplace, называемый "reverse!":

$ 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

Ответ 2

Просто для обсуждения, с таким количеством альтернатив, хорошо видеть, есть ли существенные различия в скорости/эффективности. Я немного почистил код, так как код, показывающий вывод, неоднократно менял результаты.

# 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 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 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()" ) является самой быстрой версией pure-Ruby. # 2 ( "reverse!" ) Является самым быстрым, но он использует [].reverse, который находится в C.

  • Редактировать 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)

Ответ 3

Здесь один из способов сделать это с помощью инъекции и смещения:

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

Ответ 4

Ruby-эквивалент встроенного reverse может выглядеть так:

# 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" и установить $KCODE для UTF-8.

Для решения, не связанного с 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.

Ответ 5

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

Ответ 6

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

Ответ 7

Использование

def reverse_string(string) # Method reverse_string with parameter 'string'.
  loop = string.length # int loop is equal to the string 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 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.

Ответ 8

Решение, описанное ниже. Нет необходимости выходить за пределы размера массива:

class ReverseString

  def initialize(array)
    @array = array
    @size  = @array.size
  end

  def process
    ([email protected]/2).to_a.each_with_index do |e,i|
      @array[i], @array[@size-i-1] = @array[@size-i-1], @array[i]
    end
    @array
  end

end


require 'minitest/autorun'

class ReverseStringTest < Minitest::Unit::TestCase
  def test_process
    assert_equal "9876543210", ReverseString.new("0123456789").process
  end
end

Ответ 9

Трудно читать однострочный,

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

Ответ 10

Также, используя 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"

Ответ 11

Посмотрите, как Rubinius реализует этот метод - они реализуют большую часть основной библиотеки в Ruby, и я не удивлюсь, если в Ruby реализованы String#reverse и String#reverse!.

Ответ 12

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

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

 result

end 

Ответ 14

Это решение, которое пришло мне в голову как рубиновый новичок

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")

Ответ 15

Здесь альтернатива, использующая побитовые операции 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

Ответ 16

В 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) 

Ответ 17

Я считаю, что это сработает и

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

Ответ 18

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

Если у вас есть предложение "Величайшая победа в том, что", и вы хотите иметь "это победа величайшая", вы должны использовать этот метод

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

solution("The greatest victory is that")

Ответ 20

string = "This is my string"
string_arr = string.split('')
n = string_arr.length
new_arr = Array.new

17.times do |i|
  new_arr << string_arr.values_at(n - i)
end

reversed_string = new_arr.flatten.join('')
=> "gnirts ym si sihT"

Ответ 21

Вот простая альтернатива, она сначала разбивает строку на массив, подсчитывает длину и вычитает один (из-за правила индексирования рубина для массива, начиная с 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