¿Cómo puedo eliminar un elemento de una matriz por valor?


343

Tengo una variedad de elementos en Ruby

[2,4,6,3,8]

Necesito eliminar elementos con valor, 3por ejemplo

¿Cómo puedo hacer eso?


me pregunto por qué delete array.delete(3)no funciona dentro de rubí en los carriles controlador
ImranNaqvi

2
puede deberse al active recordmétododelete
ImranNaqvi

Respuestas:


481

Creo que lo he descubierto:

a = [3, 2, 4, 6, 3, 8]
a.delete(3)
#=> 3
a
#=> [2, 4, 6, 8]

189
Personalmente me gusta lo [1, 2, 3, 4, 5] - [3]que resulta => [1, 2, 4, 5]de irb.
Travis

24
¿Qué sucede si hay varias entradas de 3 y queremos eliminar solo una de ellas? (esto está relacionado, por lo que preguntar aquí podría ser lo mejor)
Navneet

113
Solo un aviso de que .delete () devolverá el valor eliminado, no la matriz modificada con el valor eliminado.
Joshua Pinter

23
La otra consecuencia a considerar es que delete muta la matriz subyacente mientras que -crea una nueva matriz (que se le devuelve) sin el valor eliminado. Dependiendo de su caso de uso, cualquier enfoque puede tener sentido.
srt32

2
@ user3721428, delete (3) no se refiere al elemento en la posición 3, sino que elimina cualquier elemento que coincida con el entero 3. Eliminará todas las apariciones de 3 y no tiene nada que ver con el índice o la posición de los arrays.
bkunzi01

226

Tomando prestado de Travis en los comentarios, esta es una mejor respuesta:

Personalmente me gusta lo [1, 2, 7, 4, 5] - [7]que resulta => [1, 2, 4, 5]deirb

Modifiqué su respuesta al ver que 3 era el tercer elemento en su matriz de ejemplo. Esto podría generar cierta confusión para aquellos que no se dan cuenta de que 3 está en la posición 2 de la matriz.


21
Como srt32 señala en la respuesta, hay que hacer una distinción importante entre usar .deletey -. .deletedevolverá el valor que se eliminó de la matriz, si lo hay; -No lo haré. Entonces [ 1, 2, 3 ] - [ 2 ]volverá [ 1, 3 ], mientras [ 1, 2, 3 ].delete( 2 )que volverá 2.
Argus9

55
array - subArrayno funcionará para Array of Arrays , pero array.delete(subArray)lo hará.
Sachin

20
La diferencia muy importante entre [1,2,3] - [2]y [1,2,3].delete(2)es que el deletemétodo modifica la matriz original , mientras [1,2,3] - [3]crea una nueva matriz .
Timothy Kovalev el

Re subarreglos (comentario de @ Sachin arriba) "Claro que sí", solo necesitas acertar en la notación: [1,2,[2],2,3,4] - [2]te da [1, [2], 3, 4], pero [1,2,[2],2,3,4] - [[2]]te da [1, 2, 2, 3, 4]. :-)
Tom Hundt el

69

Otra opción:

a = [2,4,6,3,8]

a -= [3]

lo que resulta en

=> [2, 4, 6, 8] 

50

No estoy seguro de si alguien ha dicho esto, pero Array.delete () y - = value eliminarán cada instancia del valor que se le pase dentro de Array. Para eliminar la primera instancia del elemento en particular, podría hacer algo como

arr = [1,3,2,44,5]
arr.delete_at(arr.index(44))

#=> [1,3,2,5]

Podría haber una manera más simple. No digo que esta sea la mejor práctica, pero es algo que debería reconocerse.


1
Estaba buscando una manera de hacer esto y solo eliminar una instancia del elemento en caso de duplicados y ¡esto funciona muy bien!
xeroshogun

Creo que esta respuesta es incorrecta, simplemente porque arr.index () podría irnil
windmaomao

32

Suponiendo que desea eliminar 3 por valor en varios lugares de una matriz, creo que la forma rubí de hacer esta tarea sería utilizar el método delete_if:

[2,4,6,3,8,3].delete_if {|x| x == 3 } 

También puede usar delete_if para eliminar elementos en el escenario de 'matriz de matrices'.

Espero que esto resuelva tu consulta


25

me gusta el -=[4] forma mencionada en otras respuestas para eliminar los elementos cuyo valor es 4.

Pero hay de esta manera:

irb(main):419:0> [2,4,6,3,8,6].delete_if{|i|i==6}
=> [2, 4, 3, 8]
irb(main):420:0>

mencionado en alguna parte de " Operaciones básicas de matriz ", después de que menciona la mapfunción.


Pero no puedes simplemente usar.delete(6)
Zac

@Zac por supuesto, pero esa respuesta ya se ha mencionado (al igual que la muy concisa -=manera a-=[4]es decir a=a-[4]. [3,4]-[4], Lo que he dicho me ha gustado), pero quería hablar de otra manera posible.
barlop

Este método también tiene la ventaja de devolver la matriz en lugar del elemento eliminado.
F.Webber



15

Aquí hay algunos puntos de referencia:

require 'fruity'


class Array          
  def rodrigo_except(*values)
    self - values
  end    

  def niels_except value
    value = value.kind_of?(Array) ? value : [value]
    self - value
  end
end

ARY = [2,4,6,3,8]

compare do
  soziev  { a = ARY.dup; a.delete(3);               a }
  steve   { a = ARY.dup; a -= [3];                  a }
  barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
  rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
  niels   { a = ARY.dup; a.niels_except(3);           }
end

# >> Running each test 4096 times. Test will take about 2 seconds.
# >> soziev is similar to barlop
# >> barlop is faster than steve by 2x ± 1.0
# >> steve is faster than rodrigo by 4x ± 1.0
# >> rodrigo is similar to niels

Y de nuevo con una matriz más grande que contiene muchos duplicados:

class Array          
  def rodrigo_except(*values)
    self - values
  end    

  def niels_except value
    value = value.kind_of?(Array) ? value : [value]
    self - value
  end
end

ARY = [2,4,6,3,8] * 1000

compare do
  soziev  { a = ARY.dup; a.delete(3);               a }
  steve   { a = ARY.dup; a -= [3];                  a }
  barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
  rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
  niels   { a = ARY.dup; a.niels_except(3);           }
end

# >> Running each test 16 times. Test will take about 1 second.
# >> steve is faster than soziev by 30.000000000000004% ± 10.0%
# >> soziev is faster than barlop by 50.0% ± 10.0%
# >> barlop is faster than rodrigo by 3x ± 0.1
# >> rodrigo is similar to niels

Y aún más grande con más duplicados:

class Array          
  def rodrigo_except(*values)
    self - values
  end    

  def niels_except value
    value = value.kind_of?(Array) ? value : [value]
    self - value
  end
end

ARY = [2,4,6,3,8] * 100_000

compare do
  soziev  { a = ARY.dup; a.delete(3);               a }
  steve   { a = ARY.dup; a -= [3];                  a }
  barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
  rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
  niels   { a = ARY.dup; a.niels_except(3);           }
end

# >> Running each test once. Test will take about 6 seconds.
# >> steve is similar to soziev
# >> soziev is faster than barlop by 2x ± 0.1
# >> barlop is faster than niels by 3x ± 1.0
# >> niels is similar to rodrigo

77
Entonces, ¿cuál es el mejor? :)
Kirby

8

Mejoré la solución de Niels

class Array          
  def except(*values)
    self - values
  end    
end

Ahora puedes usar

[1, 2, 3, 4].except(3, 4) # return [1, 2]
[1, 2, 3, 4].except(4)    # return [1, 2, 3]

Su solución no funciona en la irbconsola 2.2.1 :007 > [1, 2, 3, 4].except(3, 4) NoMethodError: undefined method except for [1, 2, 3, 4]:Array from (irb):7 from /usr/share/rvm/rubies/ruby-2.2.1/bin/irb:11:in <main>
hgsongra

1
Para declarar en IRB, debe agregar el método a Array class Array; def except(*values); self - values; end; end.
Mark Swardstrom

3

También puedes mono parchearlo. Nunca entendí por qué Ruby tiene un exceptmétodo Hashpero no para Array:

class Array
  def except value
    value = value.kind_of(Array) ? value : [value]
    self - value
  end
end

Ahora puedes hacer:

[1,3,7,"436",354,nil].except(354) #=> [1,3,7,"436",nil]

O:

[1,3,7,"436",354,nil].except([354, 1]) #=> [3,7,"436",nil]

1
No necesitas la value.kind_of(Array)prueba. Solo úsalo self - Array(value).
Sasgorilla

3

Entonces, cuando tiene múltiples ocurrencias de 3 y solo desea eliminar la primera aparición de 3, simplemente puede hacer algo de la siguiente manera.

arr = [2, 4, 6, 3, 8, 10, 3, 12]

arr.delete_at arr.index 3

#This will modify arr as [2, 4, 6, 8, 10, 3, 12] where first occurrence of 3 is deleted. Returns the element deleted. In this case => 3.

3

Eliminación no destructiva de la primera aparición:

a = [2, 4, 6, 3, 8]
n = a.index 3
a.take(n)+a.drop(n+1)

2

Si también desea que esta operación de eliminación se pueda encadenar, para que pueda eliminar algún elemento y seguir encadenando operaciones en la matriz resultante, use tap:

[2, 4, 6, 3, 8].tap { |ary| ary.delete(3) }.count #=> 4

1

Compilar todas las diferentes opciones para eliminar en ruby

eliminar : elimina elementos coincidentes por valor. Si más de un valor coincide, lo eliminará todo. Si no le importa la cantidad de casos o no está seguro de una sola, use este método.

a = [2, 6, 3, 5, 3, 7]
a.delete(3)  # returns 3
puts a       # return [2, 6, 5, 7]

delete_at - Elimina el elemento en el índice dado. Si conoce el índice, use este método.

# continuing from the above example
a.delete_at(2) # returns 5
puts a         # returns [2, 6, 7]

delete_if : elimina todos los elementos para los que el bloque es verdadero. Esto modificará la matriz. La matriz cambia instantáneamente cuando se llama al bloque.

b = [1, 2, 5, 4, 9, 10, 11]
b.delete_if {|n| n >= 10}.  # returns [1, 2, 5, 4, 9]

rechazar - Esto devolverá una nueva matriz con los elementos para los cuales el bloque dado es falso. El orden se mantiene con esto.

c = [1, 2, 5, 4, 9, 10, 11]
c.reject {|n| n >= 10}.  # returns [1, 2, 5, 4, 9]

¡rechazar! - igual que delete_if . La matriz puede no cambiar instantáneamente cuando se llama al bloque.

Si desea eliminar varios valores de la matriz, la mejor opción es la siguiente.

a = [2, 3, 7, 4, 6, 21, 13]
b = [7, 21]
a = a - b    # a - [2, 3, 4, 6, 13]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.