Вывод дается в 2 строки после конкатенации элементов с нечетными и четными индексами в заданной строке

Я написал функцию, которая берет все элементы с нечетными индексами и объединяет их со всеми элементами с четными индексами в заданной строке n раз:

def encrypt(text,n)
  while n > 0
    n -= 1
    str_array = text.split("")
    even_values = str_array.select.with_index { |_, i| i.even? }
    odd_values = str_array.select.with_index { |_, i| i.odd? }
    text = (odd_values+even_values).join
  end
  puts text
end

puts 'Type your message to encrypt:'
text = gets
puts 'Type number of times to run encryption:'
n = gets.to_i
encrypt(text,n)

Проблема в том, что если входной текст имеет нечетное количество элементов, функция вернет текст в 2 строки. В то же время, если количество элементов входного текста равно четному, вывод представляет собой 1-строчный текст, чего я и хочу.

Вывод консоли с 10 элементами во входном тексте:

Type your message to encrypt:
abcdefghij 
Type number of times to run encryption:
1
bdfhjacegi

Вывод консоли с 11 элементами во входном тексте:

Type your message to encrypt:
abcdefghijk
Type number of times to run encryption:
1
bdfhj
acegik

🤔 А знаете ли вы, что...
Ruby популярен в мире искусственного интеллекта и машинного обучения.


25
1

Ответ:

Решено

Для n = 1

def doit(str)
  enum = [false, true].cycle
  str.each_char.partition { enum.next }.map(&:join).join
end
doit "abcdefghij"
  #=> "bdfhjacegi"
doit "abcdefghijk"
  #=> "bdfhjacegik"

Для n > 1

n.times.reduce(str) { |s,_| doit(s) }

Например:

4.times.reduce(str) { |s,_| doit(s) }
  #=>"ejdichbgafk"

См. Перечислимое#уменьшить (он же inject)


Теперь рассмотрим вычисления, выполненные doit.

Сначала рассмотрим перечислитель enum, созданный методом Массив#цикл:

 enum = [false, true].cycle
   #=> #<Enumerator: [false, true]:cycle>

Мы можем использовать метод Перечислитель#следующий, чтобы увидеть, какие значения будет генерировать этот перечислитель enum:

 enum.next
   #=> false
 enum.next
   #=> true
 enum.next
   #=> false
 ... ad infinitum

Теперь сбросим перечислитель с помощью Перечислитель#перемотка назад:

 enum.rewind
   #<Enumerator: [false, true]:cycle>

Предполагать

str = "abcdefghijk"

Затем

e = str.each_char
  #=> #<Enumerator: "abcdefghijk":each_char>

Мы можем преобразовать этот перечислитель в массив, чтобы посмотреть, какие элементы он сгенерирует.

e.to_a
  #=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]

Продолжая,

a = e.partition { enum.next }
  #=> [["b", "d", "f", "h", "j"], ["a", "c", "e", "g", "i", "k"]]
b = a.map(&:join)
  #=> ["bdfhj", "acegik"]  
b.join
  #=> "bdfhjacegik"

Примечание a.map(&:join) является сокращением от a.map { |arr| arr.join }.

См. Строка#each_char, Перечислимый#раздел и Массив # присоединиться.