Есть ли противоположность включить? для 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. Это не чистый Ruby, но используется большим количеством рубинов.

Источник: Active Support Core Extensions (Руководства по Rails)



3
Незначительное замечание: AS добавляет его в Enumerable, чтобы вы могли использовать его со всеми классами, включая Enumerable. Даже с Хэшем. :)
user2422869

1
Это должно быть зеленой галочкой
etlds

Этот метод больше не загружается автоматически в Rails 4.2.3 (и, возможно, раньше), вам нужноrequire 'active_support/core_ext/enumerable'
Деннис

96

Ну вот:

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

Вы можете взглянуть на Руководство по стилю Ruby для получения дополнительной информации о подобных методах.


Upvote для руководства по стилю. Просто материал для чтения, который мне был нужен.
justnorris

1
читается за одно утверждение. если много, то лучше использовать отрицание! или добавьте свой собственный метод в класс ruby ​​array.
Ренарс Сиротиньш

3
Предпочитаете это исключить? ответь как чистый рубин.
dscher

1
Но все же странно при работе с составным условием. if flag unless @players.include?(p.name)неудобно и if flag && !@players.include?(p.name)использует отрицание.
gabe

1
Пока ifпусть trueпроходит только условие, unlessпропускает falseи nil. Это иногда приводит к трудностям поиска ошибок. Поэтому я предпочитаюexclude?
ToTenMilan

12

Как насчет следующего:

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

Чувак, со скоростью, с которой приходят ответы на этом сайте, я не знаю, получу ли я какую-либо репутацию без какого-либо добросовестного кумовства! :-D Ссылка на руководство по стилю - приятное прикосновение.
ilasno

2
Дело не в том, чтобы быть быстрым. Речь идет о тщательности. (Я нашел) =)
Чарльз Колдуэлл

11

Глядя только на Ruby:

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?with exclude?намного удобнее.

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

Но, как говорит dizzy42 выше, использование 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.