Чи існує протилежне включення? для Ruby Arrays?


190

У моєму коді є така логіка:

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

@players- це масив. Чи є метод, щоб я міг уникнути !?

В ідеалі цей фрагмент буде таким:

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

1
чи doдійсний рубін? я отримую помилку syntax error, unexpected end-of-input(працює, якщо я do
видаляю

Див. Stackoverflow.com/a/60404934/128421 щодо орієнтирів для пошуку масиву проти набору.
Олов'яний чоловік

Відповіді:


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

ActiveSupport додає exclude?метод Array, Hash, і String. Це не чистий Рубін, але його використовує багато рубістів.

Джерело: Основні розширення з підтримкою (Посібники по рейках)



3
Незначне зауваження: AS додає його до Inumerable, щоб ви могли використовувати його у всіх класах, до яких належить Enumerable. Навіть з Hash. :)
user2422869

1
Це має бути зеленим
відміткою

Спосіб більше не завантажується автоматично в Rails 4.2.3 (а можливо і раніше). Вам потрібно будеrequire 'active_support/core_ext/enumerable'
Dennis

96

Ось вам:

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

Ви можете ознайомитися з посібником зі стилів Ruby для отримання додаткової інформації про подібні методи.


Резюме для керівництва зі стилем. Просто потрібний мені матеріал для читання.
justnorris

1
читабельна для одного твердження. якщо багато хто тоді краще використовувати негатив! або додати власний метод до класу масиву ruby.
Ренарс Сиротинс

3
Віддаєте перевагу цьому виключенню? відповідь, як це чистий Рубі.
dscher

1
Але все ж дивно, коли працюємо зі складною умовою. if flag unless @players.include?(p.name)незручний і if flag && !@players.include?(p.name)використовує заперечення.
Гейб

1
Хоча ifлише trueпередати умову, unlessпропустимо falseі nil. Це іноді призводить до важкого пошуку помилок. Тому я віддаю перевагуexclude?
ToTenMilan

12

Як щодо наступного:

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

Людина, зі швидкістю відповіді на цьому сайті, я не знаю, чи отримаю я репутацію без якогось доброго непотизму! :-D Посилання «Керівництво по стилю» - це приємний штрих.
ilasno

2
Справа не в тому, щоб бути швидким. Йдеться про ретельність. (Я знайшов) =)
Чарльз Колдвелл

11

Дивлячись лише на Рубі:

TL; DR

Для порівняння використовуйте none?передачу йому блоку ==:

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

Array#include?приймає один аргумент і використовує ==для перевірки кожного елемента в масиві:

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

Enumerable#none?також може прийняти один аргумент, у цьому випадку він використовує ===для порівняння. Для отримання протилежної поведінки include?опускаємо параметр і передаємо йому блок, використовуючи ==для порівняння.

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

У наведеному вище прикладі ми можемо реально використовувати:

player.none?(7)
 #=> true

Це тому, що Integer#==і Integer#===рівнозначно. Але врахуйте:

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

none?повертається falseтому, що Integer === 1 #=> true. Але дійсно законний notinclude?метод повинен повернутися true. Так, як ми робили раніше:

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

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

Гаразд, але серйозно, якщо тільки не працює добре.


1
+1 unlessце нормально для показаного фрагмента, але ця умова може бути складнішою. Я думаю, що зручно мати ці заперечувані методи, вони дозволяють отримати більше декларативного коду.
tokland


1

Чи можете ви використовувати:

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

unlessпротилежне if, або ви можете використовувати reject.

Ви можете rejectне обов'язкові елементи:

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

після отримання результатів ви можете виконати свою реалізацію.


0

Використання unlessчудово для висловлювань з одиничними include?пропозиціями, але, наприклад, коли вам потрібно перевірити включення чогось в одне, Arrayа не в інше, використання include?з exclude?набагато привітніше.

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

Але як запаморочення говорить вище, для використання exclude?потрібен ActiveSupport


Просто потрібне використання основних розширень Active Support. guides.rubyonrails.org/v3.2/…
Олов'яний чоловік

0

Спробуйте щось подібне:

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

0

Спробуйте це, чистий Ruby, тому немає необхідності додавати периферійні рамки

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

Я боровся з подібною логікою протягом декількох днів, і після перевірки декількох форумів і дощок з питань відповідей, виявилося, що рішення було насправді досить простим.


0

Я шукав це на собі, знайшов це, а потім рішення. Люди використовують заплутані методи та деякі методи, які не працюють у певних ситуаціях або взагалі не працюють.

Я знаю, що зараз уже пізно, вважаючи, що це було розміщено 6 років тому, але, сподіваємось, майбутні відвідувачі знайдуть це (і, сподіваємось, він може прибрати їхній і ваш код.)

Просте рішення:

if not @players.include?(p.name) do
  ....
end
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.