Gibt es ein Gegenteil von include? für Ruby Arrays?


190

Ich habe die folgende Logik in meinem Code:

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

@playersist ein Array. Gibt es eine Methode, um das zu vermeiden !?

Im Idealfall wäre dieses Snippet:

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

1
ist der dogültige Rubin? Ich bekomme eine Fehlermeldung syntax error, unexpected end-of-input(funktioniert, wenn ich die entferne do)
Maxymoo

Unter stackoverflow.com/a/60404934/128421 finden Sie Benchmarks für die Suche nach einem Array im Vergleich zu einem Satz.
Der Blechmann

Antworten:


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

Active fügt die exclude?Methode Array, Hashund String. Dies ist kein reiner Rubin, sondern wird von vielen Rubinisten verwendet.

Quelle: Active Support Core Extensions (Rails Guides)



3
Kleinere Bemerkung: AS fügt es Enumerable hinzu, damit Sie es mit allen Klassen verwenden können, die Enumerable enthalten. Auch mit Hash. :)
user2422869

1
Dies sollte grün angekreuzt sein
etlds

Die Methode wird in Rails 4.2.3 (und möglicherweise früher) nicht mehr automatisch geladen. Sie müssenrequire 'active_support/core_ext/enumerable'
Dennis

96

Bitte schön:

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

Weitere Informationen zu ähnlichen Techniken finden Sie im Ruby Style Guide .


Upvote für den Styleguide. Nur das Lesematerial, das ich brauchte.
Justnorris

1
lesbar für eine Aussage. wenn viele dann besser negieren! oder fügen Sie der Ruby-Array-Klasse Ihre eigene Methode hinzu.
Renars Sirotins

3
Ziehen Sie dies dem Ausschluss vor? antworte, da es reiner Rubin ist.
Dscher

1
Aber immer noch komisch, wenn man mit einer zusammengesetzten Bedingung arbeitet. if flag unless @players.include?(p.name)ist umständlich und if flag && !@players.include?(p.name)verwendet Negation.
gabe

1
Während iflet nur trueden Zustand passieren, unlesspassieren lässt falseund nil. Dies führt manchmal zu schwer zu findenden Fehlern. Deshalb bevorzuge ichexclude?
ToTenMilan

12

Wie wäre es mit folgendem:

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

Mann, mit der Geschwindigkeit, mit der Antworten auf dieser Seite eingehen, weiß ich nicht, ob ich ohne einen guten alten Nepotismus einen Ruf bekommen werde! :-D Der Style Guide Link ist eine nette Geste.
Ilasno

2
Es geht nicht darum, schnell zu sein. Es geht darum, gründlich zu sein. (Ich habe gefunden) =)
Charles Caldwell

11

Nur Ruby betrachten:

TL; DR

Verwenden none?Sie ==zum Vergleich einen Block mit :

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

Array#include?akzeptiert ein Argument und ==prüft mit jedem Element im Array:

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

Enumerable#none?kann auch ein Argument akzeptieren, in welchem ​​Fall es ===für den Vergleich verwendet wird. Um das gegenteilige Verhalten zu erreichen, lassen include?wir den Parameter weg und übergeben ihm einen Block, der ==für den Vergleich verwendet wird.

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

Im obigen Beispiel können wir tatsächlich verwenden:

player.none?(7)
 #=> true

Das liegt daran Integer#==und Integer#===sind gleichwertig. Aber bedenken Sie:

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

none?kehrt zurück, falseweil Integer === 1 #=> true. Aber wirklich eine legitime notinclude?Methode sollte zurückkehren true. Also wie vorher:

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

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

Ok, aber im Ernst, es sei denn, es funktioniert gut.


1
+1 unlessEs ist in Ordnung für das gezeigte Snippet, aber die Bedingung kann komplexer sein. Ich denke, es ist praktisch, diese negierten Methoden zu haben, sie erlauben mehr deklarativen Code.
Tokand


1

Kannst du --- benutzen:

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

unlessist das Gegenteil von if, oder Sie können verwenden reject.

Sie können rejectdie nicht benötigten Elemente:

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

Nachdem Sie die Ergebnisse erhalten haben, können Sie Ihre Implementierung durchführen.


0

Die Verwendung von unlessist für Anweisungen mit einzelnen include?Klauseln in Ordnung. Wenn Sie jedoch beispielsweise die Aufnahme von etwas in eine, Arrayaber nicht in eine andere überprüfen müssen , ist die Verwendung von include?with exclude?viel freundlicher.

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

Aber wie dizzy42 oben sagt, exclude?erfordert die Verwendung von ActiveSupport


Es müssen lediglich die Core Extensions von Active Support verwendet werden. guides.rubyonrails.org/v3.2/…
der Blechmann

0

Versuchen Sie so etwas:

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

0

Versuchen Sie dies, es ist reines Ruby, sodass keine peripheren Frameworks hinzugefügt werden müssen

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

Ich hatte einige Tage lang mit einer ähnlichen Logik zu kämpfen, und nachdem ich mehrere Foren und Q & A-Boards ohne Erfolg überprüft hatte, stellte sich heraus, dass die Lösung eigentlich ziemlich einfach war.


0

Ich habe selbst nachgesehen, dies gefunden und dann eine Lösung gefunden. Menschen verwenden verwirrende Methoden und einige Methoden, die in bestimmten Situationen nicht oder überhaupt nicht funktionieren.

Ich weiß, dass es jetzt zu spät ist, wenn man bedenkt, dass dies vor 6 Jahren veröffentlicht wurde, aber hoffentlich finden zukünftige Besucher dies (und hoffentlich kann es ihren und Ihren Code bereinigen.)

Einfache Lösung:

if not @players.include?(p.name) do
  ....
end
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.