Y a-t-il un opposé d'inclure? pour Ruby Arrays?

195

J'ai la logique suivante dans mon code:

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

@playersest un tableau. Existe-t-il une méthode pour éviter le !?

Idéalement, cet extrait serait:

if @players.does_not_include?(p.name)
  ...
end
Tyler DeWitt
la source
1
est le dorubis valide? j'obtiens une erreur syntax error, unexpected end-of-input(fonctionne si je supprime le do)
maxymoo
Voir stackoverflow.com/a/60404934/128421 pour les benchmarks de recherche d'un tableau par rapport à un ensemble.
the Tin Man le

Réponses:

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

ActiveSupport ajoute la exclude?méthode Array, Hashet String. Ce n'est pas du pur Ruby, mais est utilisé par BEAUCOUP de rubisistes.

Source: Extensions de base de support actif (guides de rails)

étourdi42
la source
6
Documentation ici
barnett
3
Remarque mineure: AS l'ajoute à Enumerable afin que vous puissiez l'utiliser avec toutes les classes qui incluent Enumerable. Même avec Hash. :)
user2422869
1
Ceci devrait être coché en vert
etlds
La méthode n'est plus chargée automatiquement dans Rails 4.2.3 (et peut-être plus tôt), vous devrezrequire 'active_support/core_ext/enumerable'
Dennis
96

Voici:

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

Vous pouvez consulter le Ruby Style Guide pour plus d'informations sur des techniques similaires.

Bozhidar Batsov
la source
Vote favorable pour le guide de style. Juste le matériel de lecture dont j'avais besoin.
justnorris
1
lisible pour une instruction. si beaucoup alors mieux utiliser nier! ou ajoutez votre propre méthode à la classe de tableau ruby.
Renars Sirotins
3
Vous préférez cela à l'exclusion? répondez car c'est du pur Ruby.
dscher
1
Mais toujours bizarre lorsque vous travaillez avec une condition composée. if flag unless @players.include?(p.name)est maladroit et if flag && [email protected]?(p.name)utilise la négation.
gabe
1
Tandis que iflaissez seulement truepasser la condition, unlesslaissez passer falseet nil. Cela conduit parfois à des bogues difficiles à trouver. Par conséquent, je préfèreexclude?
ToTenMilan
12

Que diriez-vous de ce qui suit:

unless @players.include?(p.name)
  ....
end
ilasno
la source
Mec, avec la rapidité avec laquelle les réponses arrivent sur ce site, je ne sais pas si j'aurai une réputation sans un bon vieux népotisme! :-D Le lien du guide de style est une bonne idée.
ilasno
2
Il ne s'agit pas d'être rapide. Il s'agit d'être minutieux. (J'ai trouvé) =)
Charles Caldwell
12

En regardant Ruby uniquement:

TL; DR

Utilisez en none?passant un bloc avec ==pour la comparaison:

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

Array#include?accepte un argument et utilise ==pour vérifier chaque élément du tableau:

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

Enumerable#none?peut également accepter un argument auquel cas il l'utilise ===pour la comparaison. Pour obtenir le comportement opposé, include?nous omettons le paramètre et lui passons un bloc en utilisant ==pour la comparaison.

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

Dans l'exemple ci-dessus, nous pouvons en fait utiliser:

player.none?(7)
 #=> true

C'est parce que Integer#==et Integer#===sont équivalents. Mais considérez:

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

none?revient falseparce que Integer === 1 #=> true. Mais vraiment une notinclude?méthode légitime devrait revenir true. Donc, comme nous l'avons fait auparavant:

player.none? { |e| Integer == e  }
 #=> true
glace ツ
la source
7
module Enumerable
  def does_not_include?(item)
    !include?(item)
  end
end

Ok, mais sérieusement, le moins fonctionne bien.

Jesse Wolgamott
la source
1
+1 unlessc'est correct pour l'extrait affiché, mais la condition peut être plus complexe. Je pense que c'est pratique d'avoir ces méthodes négatives, elles permettent un code plus déclaratif.
tokland
2

Utilisez unless:

unless @players.include?(p.name) do
  ...
end
Mikita Belahlazau
la source
1

Peux tu utiliser:

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

unlessest l'opposé de if, ou vous pouvez utiliser reject.

Vous pouvez rejectles éléments non requis:

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

après avoir obtenu les résultats, vous pouvez faire votre mise en œuvre.

tekuri
la source
0

L'utilisation unlessest bien pour les instructions avec des include?clauses simples mais, par exemple, lorsque vous devez vérifier l'inclusion de quelque chose dans l'une Arraymais pas dans une autre, l'utilisation de include?with exclude?est beaucoup plus conviviale.

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

Mais comme le dit vertige42 ci-dessus, l'utilisation de exclude?nécessite ActiveSupport

MoiWillWork4Food
la source
Il a juste besoin de l'utilisation des extensions principales d'Active Support. guides.rubyonrails.org/v3.2/…
the Tin Man
0

Essayez quelque chose comme ceci:

@players.include?(p.name) ? false : true
ckshei
la source
0

Essayez ceci, c'est du pur Ruby, il n'est donc pas nécessaire d'ajouter des frameworks périphériques

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

J'ai eu des difficultés avec une logique similaire pendant quelques jours, et après avoir vérifié plusieurs forums et tableaux de questions-réponses en vain, il s'est avéré que la solution était en fait assez simple.

KarmaDeli
la source
0

J'étais à la recherche de cela par moi-même, j'ai trouvé ceci, puis une solution. Les gens utilisent des méthodes déroutantes et certaines méthodes qui ne fonctionnent pas dans certaines situations ou pas du tout.

Je sais qu'il est trop tard maintenant, étant donné que cela a été publié il y a 6 ans, mais j'espère que les futurs visiteurs le trouveront (et j'espère que cela pourra nettoyer leur code et le vôtre.)

Solution simple:

if not @players.include?(p.name) do
  ....
end
Voidableryzer
la source