¿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.