Ruby each_with_index desplazamiento


84

¿Puedo definir el desplazamiento del índice en el iterador de bucle each_with_index? Mi intento directo falló:

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

Editar:

Aclaración: no quiero un desplazamiento de matriz, quiero que el índice dentro de each_with_index no comience desde 0 sino, por ejemplo, 1.


¿Qué versión de Ruby usas?
fl00r

Perdón por no escribir, pero uso Ruby 1.9.2
Mark

Respuestas:


110

En realidad, Enumerator#with_indexrecibe el desplazamiento como parámetro opcional:

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

salidas:

1: foo
2: bar
3: baz

Por cierto, creo que solo está allí en 1.9.2.


2
en 1.8.7 solo with_indexno hay parámetros, índices de0
mpapis

en realidad, es posible una respuesta aún más corta, vea la mía a continuación.
Zack Xu

50

Lo siguiente es sucinto, usando la clase Enumerator de Ruby.

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

salida

1: foo
2: bar
3: baz

Array # devuelve cada uno un enumerador, y al llamar al Enumerator # with_index se devuelve otro enumerador, al que se le pasa un bloque.


5

1) Lo más simple es sustituir en index+1lugar de indexa la función:

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

pero probablemente eso no es lo que quieres.

2) Lo siguiente que puede hacer es definir un índice diferente jdentro del bloque y usarlo en lugar del índice original:

some_array.each_with_index{|item, i| j = i + 1; some_func(item, j)}

3) Si desea utilizar el índice de esta manera a menudo, defina otro método:

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


Actualizar

Esta respuesta, que fue respondida hace unos años, ahora está obsoleta. Para los rubíes modernos, la respuesta de Zack Xu funcionará mejor.


lo malo es que se instalará incluso después de que no haya más elementos en la matriz
fl00r

@ fl00r ¿De verdad? En mi ejemplo, se detiene después de las tres.
sawa

¿Pero si el desplazamiento es 2 o 10? En su caso, la compensación es cero. Quiero decir, aquí no hay ningún desplazamiento en su (3)
fl00r

@ fl00r Simplemente cambia +1en mi código a +2o +10. Funciona también.
sawa

Dios mío, el autor editó su publicación, por lo que necesita un desplazamiento de índice, no la matriz.
fl00r

4

Si de some_indexalguna manera es significativo, entonces considere usar un hash, en lugar de una matriz.


4

Me encontré con él.

Mi solución no es necesaria es la mejor, pero funcionó para mí.

En la iteración de la vista:

solo agrega: índice + 1

Eso es todo para mí, ya que no uso ninguna referencia a esos números de índice, sino solo para mostrarlos en una lista.


3

Sí tu puedes

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

También debo notar que si el desplazamiento es mayor que el tamaño de su matriz, será un error. Porque:

some_array[1000,-1] => nil
nil.each_with_index => Error 'undefined method `each_with_index' for nil:NilClass'

¿Qué podemos hacer aquí?

 (some_array[offset..-1]||[]).each_with_index{|item, index| some_func(item, index) }

O para prevalidar la compensación:

 offset = 1000
 some_array[offset..-1].each_with_index{|item, index| some_func(item, index) } if offset <= some_array.size

Esto es pequeño hacky

UPD 2

En la medida en que actualizó su pregunta y ahora no necesita el desplazamiento de matriz, sino el desplazamiento de índice, por lo que la solución @sawa funcionará bien para usted


1

Ariel tiene razón. Esta es la mejor manera de manejar esto, y no es tan malo

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

Eso es perfectamente aceptable y mejor que la mayoría de las soluciones que he visto para esto. Siempre pensé que para esto era #inject ... bueno.


1

Otro enfoque es utilizar 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

Esto funciona en todas las versiones de ruby:

%W(one two three).zip(1..3).each do |value, index|
  puts value, index
end

Y para una matriz genérica:

a.zip(1..a.length.each do |value, index|
  puts value, index
end

falta un corchete en el segundo ejemplo.
waferthin

0
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.