Как я могу связать 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?