2017-01-14 9 views
2

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

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

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

+1

Попробуйте это: 'перечислимую = [ 'A', 'B', 'C'] each.with_index.with_object ('') # => # <Перечислитель:. # <Перечислитель: # < Перечислитель: ["a", "b", "c"]: each>: with_index>: with_object ("")> '. Элементами, сгенерированными этим перечислителем и переданными в блок, будут 'enum.to_a # => [[[" a ", 0]," "], [[" b ", 1]," "], [[" c ", 2]," "]]' Это говорит вам, как нужно записывать блок-переменные: '(char, i), result = enum.next # => [[" a ", 0]," "] ', поэтому' char # => "a"; i # => 0; result # => "" '. Примечание «результат» будет меняться в ходе вычислений. –

ответ

2

Попробуйте

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| ... } 
+0

Также 'each_with_index.with_object' может работать. – tadman

+0

Собственно, они не должны быть вложенными. Обновлено с обсуждением производительности. – akuhn

+0

Что говорит «Тест»? Иногда вещи в Ruby контр-интуитивно быстры. – tadman

1

Обе операции должны быть сделано без злоупотребления 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 
+0

'map.with_index' действительно приятно! – fanaugen

2

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

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