包含是否与之相反?对于Ruby数组?


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
maxymoo

有关搜索数组与集合的基准,请参见stackoverflow.com/a/60404934/128421
锡人

Answers:


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

的ActiveSupport增加的exclude?方法ArrayHashString。这不是纯Ruby,而是许多红宝石主义者使用的。

来源:Active Support核心扩展(指南)



3
小注释:AS将其添加到Enumerable中,因此您可以将其用于所有包含Enumerable的类中。即使使用哈希。:)
user2422869

1
这应该是绿色的勾号
etlds 2015年

该方法不再在Rails 4.2.3中(可能更早)自动加载,您需要require 'active_support/core_ext/enumerable'
Dennis

95

干得好:

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

您可以查看《Ruby样式指南》,以获取有关类似技术的更多信息。


支持样式指南。只是我需要的阅读材料。
justnorris 2013年

1
一条语句可读。如果很多的话最好用否定!或将自己的方法添加到ruby数组类。
Renars Sirotins,2014年

3
将此排除在外?回答,因为它是纯Ruby。
dscher 2013年

1
但是在处理复合条件时仍然很奇怪。if flag unless @players.include?(p.name)笨拙并且if flag && !@players.include?(p.name)使用否定。
gabe

1
iftrue通过条件时,unlessfalse和通过nil。有时这会导致难以发现错误。因此,我更喜欢exclude?
ToTenMilan '17

12

怎么样:

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

伙计,在这个网站上以快速的答案出现,我不知道如果没有一些好油ne的裙带关系,我是否会赢得声誉!:-D“样式指南”链接很不错。
ilasno 2012年

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 2012年


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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.