2010-07-15 8 views
57

Tengo una matriz que quiero iterar y eliminar algunos de los elementos. Esto no funciona:¿Cómo puedo usar Array # delete mientras itero sobre la matriz?

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] 

Quiero a ser [1, 2]. ¿Cómo puedo evitar esto?

+0

Posible duplicado de [Eliminación mientras itera en Ruby?] (Http://stackoverflow.com/questions/2933366/deleting-while-iterating-in-ruby) – sschuberth

Respuesta

101

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

Ver documentación del método here

Actualización:

Puede manejar x en el bloque:

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

Necesito hacer algo con 'x' si se pone borrado ¿Debería poner eso en el bloque? – Adrian

+0

Sí, ver mi respuesta actualizada – Chubas

+1

@Adrian O podría usar '¡rechazar!'. –

2

hice esta pregunta no hace mucho tiempo.

Deleting While Iterating in Ruby?

No está funcionando porque Rubí sale del bucle .each al intentar borrar algo. Si simplemente desea eliminar elementos de la matriz, funcionará delete_if, pero si desea tener más control, la solución que tengo en esa cadena funciona, aunque es algo desagradable.

+8

La eliminación no rompe el ciclo. 'each' efectivamente itera al usar el índice. Entonces, si elimina, los índices son diferentes, y la próxima iteración usará los nuevos índices. Pruebe esto: 'arr = [1,2,3,4,5,6]; arr.each_with_index {| e, i | p [arr, e, i]; siguiente si e <3; arr.delete e} '. Cuando se llega al elemento 3, el índice es 2. Después de que se borre 3, la siguiente iteración incrementa el índice a 3, y el ítem es 5. Entonces 4 se omite. 6 se omite por la misma razón. – Kelvin

7

Usted no tiene que eliminar de la matriz, puede filtrar por lo que:

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

Perdón por levantar una publicación de zombies pero curioso en cuanto a si el b = un subconjunto de un enfoque aumenta el uso de la memoria o si usa punteros internos o algo para referirse a los elementos originales. La razón por la que pregunto es que mi caso de uso es bastante sensible a la memoria, por lo que es curioso si eliminar el conjunto original o seleccionar es un método mejor ... – gorlaz

2

Otra forma de hacerlo es usando reject!, que es posiblemente más clara ya que tiene un ! que significa "este cambiará la matriz ". La única diferencia es que reject! devolverá nil si no se realizaron cambios.

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

o

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

hará tanto bien el trabajo.

Cuestiones relacionadas