Рубиновое смещение 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) }