C'è un contrario di include? per Ruby Arrays?


190

Ho la seguente logica nel mio codice:

if !@players.include?(p.name)
  ...
end

@playersè un array. Esiste un metodo per evitare il !?

Idealmente, questo frammento sarebbe:

if @players.does_not_include?(p.name)
  ...
end

1
è il dorubino valido? ottengo un errore syntax error, unexpected end-of-input(funziona se rimuovo il do)
maxymoo,

Vedere stackoverflow.com/a/60404934/128421 per i benchmark per la ricerca di un array rispetto a un set.
Tin Man,

Risposte:


370
if @players.exclude?(p.name)
    ...
end

ActiveSupport aggiunge il exclude?metodo Array, Hashe String. Questo non è puro rubino, ma è usato da MOLTI rubini.

Fonte: estensioni del nucleo di supporto attivo (guide di rotaie)



3
Nota minore: AS lo aggiunge a Enumerable in modo da poterlo utilizzare con tutte le classi che includono Enumerable. Anche con Hash. :)
user2422869

1
Questo è il segno di
spunta

Il metodo non viene più caricato automaticamente in Rails 4.2.3 (e possibilmente in precedenza), dovrai farlorequire 'active_support/core_ext/enumerable'
Dennis

96

Ecco qui:

unless @players.include?(p.name)
  ...
end

Potresti dare un'occhiata alla Ruby Style Guide per maggiori informazioni su tecniche simili.


Voto per la guida di stile. Solo il materiale di lettura di cui avevo bisogno.
justnorris,

1
leggibile per un'affermazione. se molti quindi meglio usare negare! o aggiungi il tuo metodo alla classe di array ruby.
Renars Sirotins,

3
Preferisci questo per escludere? rispondi perché è puro rubino.
dscher

1
Ma ancora strano quando si lavora con una condizione composta. if flag unless @players.include?(p.name)è imbarazzante e if flag && !@players.include?(p.name)usa la negazione.
Gabe,

1
Mentre iflascia truepassare solo la condizione, unlesslascia passare falsee nil. Questo a volte porta a bug difficili da trovare. Quindi preferiscoexclude?
ToTenMilan il

12

Che ne dici di quanto segue:

unless @players.include?(p.name)
  ....
end

Amico, con la velocità con cui arrivano le risposte su questo sito, non so se otterrò una reputazione senza un nepotismo buono! MrGreen Il link alla Guida di stile è un bel tocco.
ilasno,

2
Non si tratta di essere veloci. Si tratta di essere accurati. (Ho trovato) =)
Charles Caldwell,

11

Guardando solo Ruby:

TL; DR

Usa none?passandogli un blocco con ==per il confronto:

[1, 2].include?(1)
  #=> true
[1, 2].none? { |n| 1 == n  }
  #=> false

Array#include?accetta un argomento e utilizza ==per verificare ogni elemento dell'array:

player = [1, 2, 3]
player.include?(1)
 #=> true

Enumerable#none?può anche accettare un argomento nel qual caso utilizza ===per il confronto. Per ottenere il comportamento opposto include?omettiamo il parametro e passiamo un blocco usando ==per il confronto.

player.none? { |n| 7 == n }
 #=> true 
!player.include?(7)    #notice the '!'
 #=> true

Nell'esempio sopra possiamo effettivamente usare:

player.none?(7)
 #=> true

Questo perché Integer#==e Integer#===sono equivalenti. Ma considera:

player.include?(Integer)
 #=> false
player.none?(Integer)
 #=> false

none?ritorna falseperché Integer === 1 #=> true. Ma in realtà notinclude?dovrebbe tornare un metodo legittimo true. Come abbiamo fatto prima:

player.none? { |e| Integer == e  }
 #=> true

7
module Enumerable
  def does_not_include?(item)
    !include?(item)
  end
end

Ok, ma sul serio, a meno che non funzioni bene.


1
+1 unlessva bene per lo snippet mostrato, ma la condizione potrebbe essere più complessa. Penso che sia utile avere questi metodi negati, che consentono un codice più dichiarativo.
tokland


1

Puoi usare:

unless @players.include?(p.name) do
...
end

unlessè l'opposto di if, o è possibile utilizzare reject.

È possibile rejectgli elementi non richiesti:

@players.reject{|x| x==p.name}

dopo aver ottenuto i risultati è possibile eseguire l'implementazione.


0

L'uso unlessva bene per le affermazioni con singole include?clausole ma, ad esempio, quando è necessario verificare l'inclusione di qualcosa in uno Arrayma non in un altro, l'uso di include?with exclude?è molto più amichevole.

if @players.include? && @spectators.exclude? do
  ....
end

Ma come dice dizzy42 sopra, l'uso di exclude?richiede ActiveSupport


Ha solo bisogno dell'uso delle estensioni di base di Active Support. guide.rubyonrails.org/v3.2/…
the Tin Man,

0

Prova qualcosa del genere:

@players.include?(p.name) ? false : true

0

Prova questo, è puro Ruby, quindi non è necessario aggiungere alcun framework periferico

if @players.include?(p.name) == false do 
  ...
end

Ho lottato con una logica simile per alcuni giorni, e dopo aver controllato molti forum e schede di domande e risposte con scarso risultato, la soluzione era in realtà piuttosto semplice.


0

Stavo cercando su questo per me stesso, ho trovato questo e quindi una soluzione. Le persone usano metodi confusi e alcuni metodi che non funzionano in determinate situazioni o per niente.

So che è troppo tardi ora, considerando che questo è stato pubblicato 6 anni fa, ma spero che i futuri visitatori lo trovino (e si spera, può ripulire il loro e il tuo codice).

Soluzione semplice:

if not @players.include?(p.name) do
  ....
end
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.