Czy istnieje przeciwieństwo włączenia? dla Ruby Arrays?

190

W moim kodzie mam następującą logikę:

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

@playersjest tablicą. Czy istnieje metoda, dzięki której mogę uniknąć !?

Najlepiej byłoby, gdyby ten fragment był:

if @players.does_not_include?(p.name)
  ...
end
Tyler DeWitt
źródło
1
czy jest doprawidłowy rubin? dostaję błąd syntax error, unexpected end-of-input(działa, jeśli do
usunę
Zobacz stackoverflow.com/a/60404934/128421, aby zapoznać się z testami porównawczymi do przeszukiwania tablicy vs. zestawu.
Tin Man

Odpowiedzi:

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

ActiveSupport dodaje exclude?metodę Array, Hashoraz String. To nie jest czysty rubin, ale jest używany przez WIELU rubinów.

Źródło: Główne rozszerzenia Active Support (przewodniki po szynach)

dizzy42
źródło
6
Dokumentacja tutaj
Barnett
3
Drobna uwaga: AS dodaje go do Enumerable, abyś mógł używać go ze wszystkimi klasami, które zawierają Enumerable. Nawet z hashem. :)
user2422869,
1
To powinno być zaznaczone na zielono
etlds
Ta metoda nie jest już automatycznie ładowana w Railsach 4.2.3 (i być może wcześniej), musiszrequire 'active_support/core_ext/enumerable'
Dennis
96

Proszę bardzo:

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

Możesz zajrzeć do Przewodnika po stylu Ruby, aby uzyskać więcej informacji na temat podobnych technik.

Bozhidar Batsov
źródło
Głosowanie za przewodnikiem po stylu. Potrzebny mi tylko materiał do czytania.
justnorris,
1
czytelny dla jednej instrukcji. jeśli wielu, lepiej użyj negacji! lub dodaj własną metodę do klasy tablicy ruby.
Renars Sirotins
3
Wolisz to niż wykluczenie? odpowiedz, bo to czysty rubin.
dscher
1
Ale nadal dziwne, gdy pracujesz ze złożonym stanem. if flag unless @players.include?(p.name)jest niezręczny i if flag && [email protected]?(p.name)używa negacji.
gabe
1
Chociaż iftylko niech trueprzechodzą stan, unlesspozwala przejść falsei nil. To czasami prowadzi do trudnych do znalezienia błędów. Dlatego wolęexclude?
ToTenMilan
12

Co powiesz na następujące:

unless @players.include?(p.name)
  ....
end
ilasno
źródło
Człowieku, z szybkością, z jaką pojawiają się odpowiedzi na tej stronie, nie wiem, czy zdobędę reputację bez dobrego nepotyzmu! :-D Link do przewodnika po stylach to miły akcent.
ilasno
2
Tu nie chodzi o bycie szybkim. Chodzi o bycie dokładnym. (Znalazłem) =)
Charles Caldwell
11

Patrząc tylko na Ruby:

TL; DR

Użyj do porównania none?bloku z ==do:

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

Array#include?akceptuje jeden argument i używa ==do sprawdzenia każdego elementu w tablicy:

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

Enumerable#none?może również zaakceptować jeden argument, w którym to przypadku używa go ===do porównania. Aby uzyskać przeciwne zachowanie include?, pomijamy parametr i przekazujemy go do bloku za pomocą ==porównania.

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

W powyższym przykładzie możemy faktycznie użyć:

player.none?(7)
 #=> true

To dlatego, że Integer#==i Integer#===są równoważne. Ale zastanów się:

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

none?zwraca falseponieważ Integer === 1 #=> true. Ale naprawdę legalna notinclude?metoda powinna powrócić true. Tak jak wcześniej:

player.none? { |e| Integer == e  }
 #=> true
Sagar Pandya
źródło
7
module Enumerable
  def does_not_include?(item)
    !include?(item)
  end
end

Ok, ale poważnie, chyba że działa dobrze.

Jesse Wolgamott
źródło
1
+1 unlessjest w porządku dla pokazanego fragmentu, ale warunek może być bardziej złożony. Myślę, że warto mieć te zanegowane metody, które pozwalają na bardziej deklaratywny kod.
tokland
2

Użyj unless:

unless @players.include?(p.name) do
  ...
end
Mikita Belahlazau
źródło
1

Czy możesz użyć:

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

unlessjest przeciwieństwem iflub możesz użyć reject.

Możesz rejectniepotrzebne elementy:

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

po uzyskaniu wyników możesz wykonać swoją implementację.

tekuri
źródło
0

Używanie unlessjest w porządku dla instrukcji z pojedynczymi include?klauzulami, ale na przykład, gdy trzeba sprawdzić włączenie czegoś w jednym, Arrayale nie w drugim, użycie include?z exclude?jest znacznie bardziej przyjazne.

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

Ale jak mówi dizzy42 powyżej, użycie exclude?wymaga ActiveSupport

MeWillWork4Food
źródło
Po prostu potrzebuje użycia podstawowych rozszerzeń Active Support. guide.rubyonrails.org/v3.2/…
Tin Man
0

Wypróbuj coś takiego:

@players.include?(p.name) ? false : true
Ckshei
źródło
0

Spróbuj, to jest czysty Ruby, więc nie trzeba dodawać żadnych peryferyjnych ram

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

Przez kilka dni zmagałem się z podobną logiką, a po sprawdzeniu kilku forów i forum pytań i odpowiedzi okazało się, że rozwiązanie było dość proste.

KarmaDeli
źródło
0

Patrzyłem na to dla siebie, znalazłem to, a potem rozwiązanie. Ludzie używają mylących metod i niektórych metod, które nie działają w określonych sytuacjach lub wcale.

Wiem, że jest już za późno, biorąc pod uwagę, że został opublikowany 6 lat temu, ale mam nadzieję, że przyszli odwiedzający to znajdą (i mam nadzieję, że to może wyczyścić ich i twój kod).

Proste rozwiązanie:

if not @players.include?(p.name) do
  ....
end
Voidableryzer
źródło