Рубі кожне зі зміщенням індексу


84

Чи можу я визначити зміщення індексу в ітераторі циклу each_with_index? Моя пряма спроба не вдалася:

some_array.each_with_index{|item, index = 1| some_func(item, index) }

Редагувати:

Уточнення: я не хочу зміщення масиву, я хочу, щоб індекс в межах кожного_з_індексом починався не з 0, а наприклад, з 1


яку версію Ruby ви використовуєте?
fl00r

Вибачте, що не написав, але я використовую Ruby 1.9.2
Марк

Відповіді:


110

Власне, 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
в 1.8.7 це лише with_indexвідсутні параметри, індекси від0
mpapis

насправді можлива ще коротша відповідь, будь ласка, дивіться мою нижче.
Zack Xu

50

Далі є стислим, за допомогою класу Ruby's Enumerator.

[:foo, :bar, :baz].each.with_index(1) do |elem, i|
    puts "#{i}: #{elem}"
end

вихід

1: foo
2: bar
3: baz

Кожен масив # повертає перечислювач, а виклик Enumerator # with_index повертає інший перераховувач, якому передається блок.


5

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


Оновлення

Ця відповідь, на яку відповіли кілька років тому, зараз застаріла. Для сучасних рубінів відповідь Зака ​​Сю буде працювати краще.


погана річ, що він буде ітераціювати навіть після того, як у масиві більше не буде елементів
fl00r

@ fl00r Дійсно? У моєму прикладі це зупиняється після трьох.
sawa

Але якщо зсув 2 або 10? У вашому випадку зміщення дорівнює нулю. Я маю на увазі, що у Вашому (3)
fl00r

@ fl00r Ви просто змінили +1мій код на +2або +10. Це також працює.
sawa

OMG, автор відредагував свою публікацію, тому йому потрібно зміщення індексу, а не масиву.
fl00r


4

Я натрапив на це.

Моє рішення не є найкращим, але воно просто спрацювало для мене.

У ітерації подання:

просто додайте: index + 1

Це все для мене, оскільки я не використовую жодного посилання на ці номери індексу, а лише для показу у списку.


3

Так, ти можеш

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 буде добре працювати для вас


1

Аріель має рацію. Це найкращий спосіб вирішити це, і це не так вже й погано

ary.each_with_index do |a, i|
  puts i + 1
  #other code
end

Це цілком прийнятно і краще, ніж більшість рішень, які я бачив для цього. Я завжди думав, що саме для цього призначений #inject ... ну добре.


1

Інший підхід - використання 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) }

1

Це працює в кожній рубіновій версії:

%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

у другому прикладі відсутня дужка.
вафля

0
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.