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

Tamik Soziev
fuente
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]
Tamik Soziev
fuente
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.

Abram
fuente
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] 
Steve
fuente
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.

Scott
fuente
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

Sayan
fuente
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.

barlop
fuente
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
22

Simplemente puede ejecutar:

[2,4,6,3,8].delete(3)
rilutham
fuente
20

A .delete_at(3) 3aquí está la posición.

Un acantilado
fuente
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
el hombre de hojalata
fuente
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]
Rodrigo Mendonça
fuente
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]
Niels Kristian
fuente
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.
ashan priyadarshana
fuente
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)
Lori
fuente
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
dgilperez
fuente
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]
Ankit Agrawal
fuente