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.

marca
fuente
¿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.

Mladen Jablanović
fuente
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.

Zack Xu
fuente
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.

sawa
fuente
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.

Andrew Grimm
fuente
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.

Ariel De La Rosa
fuente
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

fl00r
fuente
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.

boulder_ruby
fuente
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) }
Andrew Grimm
fuente
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
fotanus
fuente
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) }
ipsum
fuente