2013-08-13 15 views
8

In Ruby è brutto usare i for-loops. Questo è comunemente capito. una guida di stile consigliato a me: (https://github.com/bbatsov/ruby-style-guide#source-code-layout) dice:Come sostituire un ciclo for in Ruby?

"Non usare mai per, se non si conosce esattamente il motivo per cui maggior parte dei iteratori tempo dovrebbe essere usato al posto di è implementato in termini di ciascuno (così.. stai aggiungendo un livello di riferimento indiretto), ma con una svolta - perché non introduce un nuovo ambito (diversamente da ciascuno) e le variabili definite nel suo blocco saranno visibili al di fuori di esso. "

L'esempio dato è:

arr = [1, 2, 3] 

#bad 
for elem in arr do 
    puts elem 
end 

# good 
arr.each { |elem| puts elem } 

ho studiato e non riesco a trovare una spiegazione su come simulare un ciclo for che fornisce un valore di iterazione posso passare a luoghi o eseguire operazioni aritmetiche su . Per esempio, con quello che dovrei sostituire:

for i in 0...size do 
    puts array1[i] 
    puts array2[size-1 - i] 
    puts i % 2 
end 

E 'facile se si tratta di un array, ma ho spesso bisogno la posizione corrente per altri scopi. C'è una soluzione semplice che mi manca, o situazioni in cui è richiesto per. Inoltre, sento che le persone parlano di per come se non fosse mai necessario. Qual è quindi la loro soluzione a questo?

Può essere migliorato? E qual è la soluzione, se ce n'è una? Grazie.

risposta

10

Se si desidera iterare su una collezione e tenere traccia dell'indice, utilizzare each_with_index:

fields = ["name", "age", "height"] 

fields.each_with_index do |field,i| 
    puts "#{i}. #{field}" # 0. name, 1. age, 2. height 
end 

tuo for i in 0...size esempio diventa:

array1.each_with_index do |item, i| 
    puts item 
    puts array2[size-1 - i] 
    puts i % 2 
end 
+0

Supponendo che 'array1' e' array2' abbiano la stessa dimensione, è meglio scrivere come 'array2 [-1 - i]' in modo da evitare di dover calcolare 'size'. – Borodin

3

Non dimenticare che si può fare cose interessanti come questa

fields = ["name", "age", "height"] 

def output name, idx 
    puts "#{idx}. #{name}" 
end 

fields.each_with_index &method(:output) 

uscita

0. name 
1. age 
2. height 

È possibile utilizzare questa tecnica come metodo di classe o istanza troppo

class Printer 
    def self.output data 
    puts "raw: #{data}" 
    end 
end 

class Kanon < Printer 
    def initialize prefix 
    @prefix = prefix 
    end 
    def output data 
    puts "#{@prefix}: #{data}" 
    end 
end 

def print printer, data 
    # separating the block from `each` allows 
    # you to do interesting things 
    data.each &printer.method(:output) 
end 

metodo esempio utilizzando la classe

print Printer, ["a", "b", "c"] 
# raw: a 
# raw: b 
# raw: c 

metodo esempio utilizzando esempio

kanon = Kanon.new "kanon prints pretty" 
print kanon, ["a", "b", "c"] 
# kanon prints pretty: a 
# kanon prints pretty: b 
# kanon prints pretty: c 
+0

Si potrebbe, ma perché dovresti? Cosa aggiunge veramente questo? – meagar

+0

Separa il blocco dall'iterazione "each *". Ciò significa che puoi tenere il blocco dove vuoi; potrebbe essere un metodo di classe o di istanza, potrebbe essere un proc dinamico, ecc. Solo dimostrando una certa flessibilità visto che l'OP sembra essere relativamente verde. Avendo ricevuto +2, già, non penso di essere l'unico che trova utile anche questo. – naomik

+0

Sono d'accordo che è utile, ma che non lo rende rilevante o in tema. Questo non è utile nella situazione descritta dalla domanda. – meagar