Рубиновое смещение each_with_index
Можно ли определить смещение индекса в итераторе цикла each_with_index?
Моя попытка прямого провала не удалась:
some_array.each_with_index{|item, index = 1| some_func(item, index) }
Edit:
Уточнение: мне не требуется смещение массива, я хочу, чтобы индекс внутри each_with_index не начинался с 0, но, например, 1.
Ответы
Ответ 1
Фактически, Enumerator#with_index
получает смещение как необязательный параметр:
[:foo, :bar, :baz].to_enum.with_index(1).each do |elem, i|
puts "#{i}: #{elem}"
end
выходы:
1: foo
2: bar
3: baz
Кстати, я думаю, что он существует только в 1.9.2.
Ответ 2
Ниже приводится краткое описание с использованием класса Ruby Enumerator.
[:foo, :bar, :baz].each.with_index(1) do |elem, i|
puts "#{i}: #{elem}"
end
Выход
1: foo
2: bar
3: baz
Array # каждый возвращает перечислитель, а вызов Enumerator # with_index возвращает другой перечислитель, которому передается блок.
Ответ 3
1) Самое простое - заменить index+1
вместо index
на функцию:
some_array.each_with_index{|item, index| some_func(item, index+1)}
но, вероятно, это не то, что вы хотите.
2) Следующее, что вы можете сделать, это определить другой индекс j
внутри блока и использовать его вместо исходного индекса:
some_array.each_with_index{|item, i| j = i + 1; some_func(item, j)}
3) Если вы хотите часто использовать индекс таким образом, определите другой метод:
module Enumerable
def each_with_index_from_one *args, &pr
each_with_index(*args){|obj, i| pr.call(obj, i+1)}
end
end
%w(one two three).each_with_index_from_one{|w, i| puts "#{i}. #{w}"}
# =>
1. one
2. two
3. three
Обновление
Этот ответ, на который был дан ответ несколько лет назад, теперь устарел. Для современных Rubies ответ Zack Xu будет работать лучше.
Ответ 4
Если some_index
как-то значимо, тогда рассмотрите использование хэша, а не массив.
Ответ 5
Я столкнулся с этим.
Мое решение не является необходимым, но это просто сработало для меня.
В итерации просмотра:
просто добавьте: index + 1
Это все для меня, поскольку я не использую ссылки на эти номера индексов, а просто для показа в списке.
Ответ 6
Да, вы можете
some_array[offset..-1].each_with_index{|item, index| some_func(item, index) }
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
some_array[offset..-1].each_with_index{|item, index| index+=offset; some_func(item, index) }
UPD
Также я должен заметить, что если смещение больше, чем размер вашего массива, то это будет ошибка. Потому что:
some_array[1000,-1] => nil
nil.each_with_index => Error 'undefined method `each_with_index' for nil:NilClass'
Что мы можем сделать здесь:
(some_array[offset..-1]||[]).each_with_index{|item, index| some_func(item, index) }
Или превалировать смещение:
offset = 1000
some_array[offset..-1].each_with_index{|item, index| some_func(item, index) } if offset <= some_array.size
Это немного хакерский
UPD 2
Насколько вы обновили свой вопрос, и теперь вам не нужно смещение массива, но смещение индекса так, что решение @sawa будет отлично работать для вас.
Ответ 7
Ариэль прав. Это лучший способ справиться с этим, и это не так уж плохо.
ary.each_with_index do |a, i|
puts i + 1
#other code
end
Это совершенно приемлемо и лучше, чем большинство решений, которые я видел для этого. Я всегда думал, что это то, что было #incject для... ну, хорошо.
Ответ 8
Другой подход заключается в использовании map
some_array = [:foo, :bar, :baz]
some_array_plus_offset_index = some_array.each_with_index.map {|item, i| [item, i + 1]}
some_array_plus_offset_index.each{|item, offset_index| some_func(item, offset_index) }
Ответ 9
Это работает в каждой рубиновой версии:
%W(one two three).zip(1..3).each do |value, index|
puts value, index
end
И для общего массива:
a.zip(1..a.length.each do |value, index|
puts value, index
end
Ответ 10
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }