2010-07-15 5 views
57

Ho una matrice che voglio ripetere e cancellare alcuni elementi. Questo non funziona:Come posso utilizzare l'eliminazione n. Array durante l'iterazione sull'array?

a = [1, 2, 3, 4, 5] 
a.each do |x| 
    next if x < 3 
    a.delete x 
    # do something with x 
end 
a #=> [1, 2, 4] 

voglio a essere [1, 2]. Come posso aggirare questo?

+0

Possibile duplicato di [Eliminazione durante l'iterazione in Ruby?] (Http://stackoverflow.com/questions/2933366/deleting-while-iterating-in-ruby) – sschuberth

risposta

101

a.delete_if { |x| x >= 3 }

veda il metodo documentazione here

Aggiornamento:

È possibile gestire x nel blocco:

a.delete_if do |element| 
    if element >= 3 
    do_something_with(element) 
    true # Make sure the if statement returns true, so it gets marked for deletion 
    end 
end 
+1

Ho bisogno di fare qualcosa con 'x' se ottiene cancellato. Dovrei metterlo nel blocco? – Adrian

+0

Sì, guarda la mia risposta aggiornata – Chubas

+1

@Adrian Oppure potresti usare "reject!". –

2

Ho fatto questa domanda non molto tempo fa.

Deleting While Iterating in Ruby?

Non funziona perché Rubino esce dal ciclo .each quando si tenta di cancellare qualcosa. Se vuoi semplicemente eliminare le cose dall'array, il lavoro delete_if funzionerà, ma se vuoi un maggiore controllo, la soluzione che ho in quel thread funziona, anche se è un po 'brutta.

+8

La cancellazione non interrompe il ciclo. 'each' efficacemente itera usando l'indice. Quindi, se elimini, gli indici sono diversi e l'iterazione successiva utilizzerà i nuovi indici. Prova questo: 'arr = [1,2,3,4,5,6]; arr.each_with_index {| e, i | p [arr, e, i]; next if e <3; arr.delete e} '. Quando viene raggiunto l'elemento 3, l'indice è 2. Dopo che 3 è stato eliminato, l'iterazione successiva aumenta l'indice a 3 e l'elemento è 5. Quindi 4 viene saltato. 6 viene saltato per lo stesso motivo. – Kelvin

7

Non è necessario eliminare dalla matrice, è possibile filtrare in modo:

a = [1, 2, 3, 4, 5] 

b = a.select {|x| x < 3} 

puts b.inspect # => [1,2] 

b.each {|i| puts i} # do something to each here 
+0

Mi spiace sollevare un post di zombi ma curioso sul fatto che il b = un sottoinsieme di un approccio accresca l'utilizzo della memoria o se usi puntatori interni o qualcosa per riferirsi all'originale a un oggetto? Motivo che chiedo è il mio caso d'uso è abbastanza sensibile alla memoria così curioso di sapere se l'eliminazione dall'array originale o selezionare è un metodo migliore ... – gorlaz

2

Un altro modo per farlo sta usando reject!, che è probabilmente più chiara in quanto ha un ! che significa "questo cambierà l'array ". L'unica differenza è che restituirà nil se non sono state apportate modifiche.

a.delete_if {|x| x >= 3 } 

o

a.reject! {|x| x >= 3 } 

saranno entrambi funzionano bene.

Problemi correlati