Как я могу связать with_index и with_object для перечислимого в ruby?

Я хочу обработать массив ['a', 'b', 'c'] вернуть строку '0a1b2c' (т. е. строка, образованная путем объединения каждого индекса с его значением).

Я могу сделать это:

result = ''
['a', 'b', 'c'].each.with_index do |char, i|
  result += "#{i}#{char}"
end  
result

Я хочу исключить переменную результата за пределами блока с помощью with_object.

Что-то вроде этого:

['a', 'b', 'c'].each.with_index.with_object('') do |char, i, result|
  result += "#{i}#{char}"
end

Но это вызывает ошибку undefined method '+' for nil:NilClass

3 ответа

Попробуй это

arr.each.with_index.with_object('') { |(each, n), obj| ... }

Как это работает?

  • Применяя оба with_index а также with_object создает вложенные кортежи
  • (each, n), obj распаковывает оба кортежа

Забавный факт - или, может быть, довольно печальный факт - вложенный кортеж фактически материализовался как недолговечный массив, так что это создаст O(n) массивы. Если это критический производственный код, я бы удалил эти две функции перечисления. Так как вы, скорее всего, собираетесь назначить obj в любом случае для переменной во внешней области было бы наиболее разумно переписать это как

obj = ''
arr.each_with_index { |each, n| ... }

Он не использует методы, которые вы запрашиваете, но он выполняет свою работу и является относительно компактным:

array = ['a', 'b', 'c']
(0...array.size).zip(array).join
#=> "0a1b2c"

Обе операции должны быть выполнены без злоупотребления each итератор:

%w|a b c|.map.with_index do |char, i|
  "#{i}#{char}"
end.join

%w|a b c|.each_with_object('').with_index do |(char, result), i|
  result << "#{i}#{char}"
end

Или, если вы все еще хотите использовать каждый:

%w|a b c|.each.with_index.with_object('') do |char_idx, result|
  result << char_idx.join
end

Что-то важное в этом решении, что приятно:

%w|a b c|.each_with_object('').with_index do |(char, result), i|
  result << "#{i}#{char}"
end

Здесь мы используем << вместо +=.

with_object работает только с изменяемыми объектами, и вы можете подумать, что строка изменяема, так почему бы нам не использовать +=? Потому как += эквивалентно x = x+y, поэтому он каждый раз генерирует новый объект.

В конце концов, если вы используете += с участием with_object, вы никогда не изменяете исходный объект, который вы создали, вы просто создаете новый объект, который вы не будете отслеживать в блоке на каждой итерации.

Подробнее здесь: Как должен работать each_with_object?

Другие вопросы по тегам