Come posso eliminare un elemento da un array in base al valore


343

Ho una serie di elementi in Ruby

[2,4,6,3,8]

Ho bisogno di rimuovere elementi con valore 3per esempio

Come lo faccio?


mi chiedo perché delete array.delete(3)non
funzioni con

2
potrebbe essere dovuto al active recordmetododelete
ImranNaqvi,

Risposte:


481

Penso di averlo capito:

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

189
Personalmente, come [1, 2, 3, 4, 5] - [3]che si traduce in => [1, 2, 4, 5]da irb.
Travis,

24
E se ci fossero più voci di 3 e volessimo eliminarne solo una? (Questo è collegato, quindi chiedere questo qui potrebbe essere il migliore)
Navneet,

113
Solo un avvertimento che .delete () restituirà il valore eliminato, non l'array modificato con il valore rimosso.
Joshua Pinter,

23
L'altra conseguenza da considerare è che deletemuta l'array sottostante mentre -crea un nuovo array (che ti viene restituito) senza il valore eliminato. A seconda del caso d'uso, entrambi gli approcci possono avere senso.
srt32,

2
@ user3721428, delete (3) non si riferisce all'elemento in posizione 3 ma elimina invece qualsiasi elemento corrispondente all'intero 3. Rimuoverà tutte le occorrenze di 3 e non ha nulla a che fare con l'indice o la posizione delle matrici.
bkunzi01,

226

Prendendo in prestito Travis nei commenti, questa è una risposta migliore:

Personalmente, come [1, 2, 7, 4, 5] - [7]che si traduce in => [1, 2, 4, 5]dairb

Ho modificato la sua risposta vedendo che 3 era il terzo elemento nella sua matrice di esempio. Ciò potrebbe creare confusione per coloro che non si rendono conto che 3 è nella posizione 2 dell'array.


21
Come sottolinea srt32 nella risposta, c'è una distinzione importante da fare tra l'utilizzo di .deletee -. .deleterestituirà il valore che è stato rimosso dall'array, se presente; -no. Quindi [ 1, 2, 3 ] - [ 2 ]tornerà [ 1, 3 ], mentre [ 1, 2, 3 ].delete( 2 )tornerà 2.
Argus9,

5
array - subArraynon funzionerà per Array of Arrays , ma array.delete(subArray)funzionerà.
Sachin,

21
La differenza molto importante tra [1,2,3] - [2]e [1,2,3].delete(2)è che il deletemetodo modifica l'array originale , mentre [1,2,3] - [3]crea un nuovo array .
Timothy Kovalev,

Re subarrays (commento di @Sachin sopra) "Certo che lo farà", devi solo prendere la notazione giusta: [1,2,[2],2,3,4] - [2]ti dà [1, [2], 3, 4], ma [1,2,[2],2,3,4] - [[2]]ti dà [1, 2, 2, 3, 4]. :-)
Tom Hundt,

69

Un'altra opzione:

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

a -= [3]

che risulta in

=> [2, 4, 6, 8] 

50

Non sono sicuro che qualcuno l'abbia dichiarato, ma Array.delete () e - = value elimineranno ogni istanza del valore passato all'interno dell'array. Al fine di eliminare la prima istanza dell'elemento particolare è possibile fare qualcosa di simile

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

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

Potrebbe esserci un modo più semplice. Non sto dicendo che questa è la migliore pratica, ma è qualcosa che dovrebbe essere riconosciuto.


1
Stavo cercando un modo per farlo ed eliminare solo un'istanza dell'elemento in caso di duplicati e questo funziona alla grande!
xeroshogun,

Penso che questa risposta sia sbagliata, semplicemente perché arr.index () potrebbe andarenil
windmaomao,

32

Supponendo che si desideri eliminare 3 in base al valore in più punti di un array, penso che il modo ruby ​​per eseguire questa attività sarebbe utilizzare il metodo delete_if:

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

Puoi anche usare delete_if per rimuovere elementi nello scenario di "array di matrici".

Spero che questo risolva la tua domanda


25

mi piace il -=[4] modo menzionato in altre risposte per eliminare gli elementi il ​​cui valore è 4.

Ma c'è così:

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

menzionato da qualche parte in " Operazioni di base sull'array ", dopo che menziona la mapfunzione.


Ma non puoi semplicemente usare.delete(6)
Zac

@Zac, naturalmente, ma la risposta è già stato menzionato (così come il molto conciso -=modo a-=[4] cioè a=a-[4]. [3,4]-[4], Che ho detto mi è piaciuto), ma ho voluto citare un altro modo possibile.
barlop

Questo metodo ha anche il vantaggio di restituire l'array anziché l'elemento eliminato.
F.Webber,



15

Ecco alcuni parametri di riferimento:

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

E ancora con un array più grande che contiene molti duplicati:

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

E ancora più grande con più duplicati:

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

7
Allora, qual è il migliore? :)
Kirby,

8

Ho migliorato la soluzione di Niels

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

Ora puoi usare

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

La tua soluzione non funziona su irbconsole 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
Per dichiarare in IRB, è necessario aggiungere il metodo all'array class Array; def except(*values); self - values; end; end.
Mark Swardstrom

3

Puoi anche scimmia patch. Non ho mai capito perché Ruby abbia un exceptmetodo per Hashma non per Array:

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

Ora puoi fare:

[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
Non hai bisogno del value.kind_of(Array)test. Basta usare self - Array(value).
Sasgorilla,

3

Quindi quando hai più occorrenze di 3 e vuoi solo eliminare la prima occorrenza di 3, puoi semplicemente fare qualcosa come di seguito.

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

Rimozione non distruttiva della prima occorrenza:

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

2

Se si desidera anche rendere questa operazione di eliminazione concatenabile, in modo da poter eliminare alcuni elementi e continuare a concatenare le operazioni sull'array risultante, utilizzare tap:

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

1

Compilando tutte le diverse opzioni per l'eliminazione in ruby

elimina : elimina gli elementi corrispondenti in base al valore. Se più di un valore corrisponde rimuoverà tutto. Se non ti interessa il numero di occorrenze o sei sicuro di una singola occorrenza, utilizza questo metodo.

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

delete_at - Elimina l'elemento in un determinato indice. Se conosci l'indice usa questo metodo.

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

delete_if - Elimina tutti gli elementi per i quali il blocco è vero. Questo modificherà l'array. La matrice cambia istantaneamente quando viene chiamato il blocco.

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

Rifiuta : questo restituirà un nuovo array con gli elementi per i quali il blocco dato è falso. L'ordinamento è mantenuto con questo.

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

rifiutare! - uguale a delete_if . L'array potrebbe non cambiare istantaneamente quando viene chiamato il blocco.

Se si desidera eliminare più valori dall'array, l'opzione migliore è la seguente.

a = [2, 3, 7, 4, 6, 21, 13]
b = [7, 21]
a = a - b    # a - [2, 3, 4, 6, 13]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.