Ruby ogni_con_indice offset


84

Posso definire l'offset dell'indice nell'iteratore del ciclo each_with_index? Il mio tentativo diretto è fallito:

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

Modificare:

Chiarimento: non voglio un offset di array, voglio che l'indice all'interno di each_with_index non inizi da 0 ma ad es.


che versione di Ruby usi?
fl00r

Scusa per non aver scritto, ma uso Ruby 1.9.2
Mark

Risposte:


110

In realtà, Enumerator#with_indexriceve offset come parametro opzionale:

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

uscite:

1: foo
2: bar
3: baz

A proposito, penso che sia presente solo nella 1.9.2.


2
in 1.8.7 è solo with_indexnessun parametro, indici da0
mpapis

in realtà, è possibile una risposta ancora più breve, vedere la mia sotto.
Zack Xu

50

Quanto segue è succinto, utilizzando la classe Enumerator di Ruby.

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

produzione

1: foo
2: bar
3: baz

Ciascun array # restituisce un enumeratore e la chiamata all'enumeratore # with_index restituisce un altro enumeratore a cui viene passato un blocco.


5

1) Il più semplice è sostituire al index+1posto della indexfunzione:

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

ma probabilmente non è quello che vuoi.

2) La prossima cosa che puoi fare è definire un indice diverso jall'interno del blocco e usarlo al posto dell'indice originale:

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

3) Se vuoi usare spesso index in questo modo, definisci un altro metodo:

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


Aggiornare

Questa risposta, a cui è stata data una risposta alcuni anni fa, è ormai obsoleta. Per i Rubini moderni, la risposta di Zack Xu funzionerà meglio.


la cosa brutta che verrà visualizzato anche dopo che non ci sono più elementi nell'array
fl00r

@ fl00r Davvero? Nel mio esempio, si ferma dopo le tre.
sawa

Ma se l'offset è 2 o 10? Nel tuo caso l'offset è zero. Voglio dire, qui non c'è alcun offset nel tuo (3)
fl00r

@ fl00r Devi solo cambiare il +1nel mio codice in +2o +10. Funziona anche lui.
sawa

OMG, l'autore ha modificato il suo post, quindi ha bisogno dell'offset dell'indice non dell'array.
fl00r

4

Se some_indexè in qualche modo significativo, considera l'utilizzo di un hash, piuttosto che un array.


4

Mi sono imbattuto in esso.

La mia soluzione non necessaria è la migliore, ma ha funzionato per me.

Nell'iterazione della vista:

basta aggiungere: indice + 1

Questo è tutto per me, poiché non uso alcun riferimento a quei numeri di indice ma solo per mostrarli in un elenco.


3

Si, puoi

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

Inoltre dovrei notare che se l'offset è maggiore della dimensione dell'array, sarà comunque un errore. Perché:

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

Cosa possiamo fare qui:

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

O per prevalidare l'offset:

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

Questo è un po 'hacky

UPD 2

Per quanto riguarda l'aggiornamento della domanda e ora non è necessario l'offset dell'array, ma l'offset dell'indice, quindi la soluzione @sawa funzionerà bene per te


1

Ariel ha ragione. Questo è il modo migliore per gestirlo, e non è poi così male

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

Questo è perfettamente accettabile e migliore della maggior parte delle soluzioni che ho visto per questo. Ho sempre pensato che questo fosse lo scopo di #inject ... oh, va bene.


1

Un altro approccio è usare 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

Funziona in ogni versione di rubino:

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

E per un array generico:

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

manca una parentesi nel secondo esempio.
waferthin

0
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.