Existe um oposto de incluir? para matrizes Ruby?


190

Eu tenho a seguinte lógica no meu código:

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

@playersé uma matriz. Existe um método para que eu possa evitar o !?

Idealmente, esse snippet seria:

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

1
o doruby é válido? Eu recebo um erro syntax error, unexpected end-of-input(funciona se eu remover o do)
maxymoo

Consulte stackoverflow.com/a/60404934/128421 para obter benchmarks para pesquisar uma matriz versus um conjunto.
o homem de lata

Respostas:


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

ActiveSupport adiciona o exclude?método para Array, Hash, e String. Isso não é puro Ruby, mas é usado por muitos rubiistas.

Fonte: Extensões principais do suporte ativo (guias de Rails)



3
Observação secundária: o AS o adiciona ao Enumerable para que você possa usá-lo com todas as classes que incluem Enumerable. Mesmo com Hash. :)
user2422869

1
Este é deve ser verde assinalada
etlds

O método não é mais carregado automaticamente no Rails 4.2.3 (e possivelmente mais cedo), você precisará #require 'active_support/core_ext/enumerable'
Dennis

96

Aqui está:

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

Você pode dar uma olhada no Ruby Style Guide para obter mais informações sobre técnicas semelhantes.


Voto positivo para o guia de estilo. Apenas o material de leitura que eu precisava.
justnorris

1
legível para uma declaração. se muitos então melhor usar negar! ou adicione seu próprio método à classe de array ruby.
Renars Sirotins

3
Prefere isso ao excluir? responda como é puro Ruby.
dscher

1
Mas ainda assim estranho ao trabalhar com uma condição composta. if flag unless @players.include?(p.name)é estranho e if flag && !@players.include?(p.name)usa negação.
gabe

1
Enquanto ifdeixar apenas truepassar a condição, unlessvamos passar falsee nil. Às vezes, isso leva a erros difíceis de encontrar. Portanto, eu prefiroexclude?
ToTenMilan

12

Que tal o seguinte:

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

Cara, com a rapidez com que as respostas chegam neste site, não sei se vou ter alguma reputação sem um nepotismo bom! :-D O link do Guia de estilo é um toque agradável.
Ilasno

2
Não se trata de ser rápido. É sobre ser completo. (Eu encontrei) =) #
9781 Charles Caldwell

11

Olhando apenas para Ruby:

TL; DR

Use none?passar um bloco com ==para a comparação:

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

Array#include?aceita um argumento e usa ==para verificar contra cada elemento na matriz:

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

Enumerable#none?também pode aceitar um argumento; nesse caso, ele é usado ===para a comparação. Para obter o comportamento oposto include?, omitimos o parâmetro e passamos um bloco ==para a comparação.

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

No exemplo acima, podemos realmente usar:

player.none?(7)
 #=> true

Isso é porque Integer#==e Integer#===é equivalente. Mas considere:

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

none?retorna falseporque Integer === 1 #=> true. Mas realmente um notinclude?método legítimo deve retornar true. Assim como fizemos antes:

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

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

Ok, mas sério, a menos que funcione bem.


1
+1 unlessestá ok para o snippet exibido, mas a condição pode ser mais complexa. Eu acho que é útil ter esses métodos negados, eles permitem mais código declarativo.
tokland


1

Você pode usar:

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

unlessé o oposto de if, ou você pode usar reject.

Você pode rejectos elementos não necessários:

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

após a obtenção dos resultados, você pode fazer sua implementação.


0

Usar unlessé bom para instruções com include?cláusulas únicas , mas, por exemplo, quando você precisa verificar a inclusão de algo em um, Arraymas não em outro, o uso de include?with exclude?é muito mais amigável.

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

Mas, como dizzy42 diz acima, o uso de exclude?requer ActiveSupport


Ele só precisa do uso das principais extensões do Active Support. Guides.rubyonrails.org/v3.2/…
o homem de lata

0

Tente algo como isto:

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

0

Tente isso, é puro Ruby, portanto não há necessidade de adicionar estruturas periféricas

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

Eu estava lutando com uma lógica semelhante por alguns dias e, depois de verificar vários fóruns e quadros de perguntas e respostas com pouco proveito, a solução era realmente bastante simples.


0

Eu estava pesquisando por mim mesmo, encontrei isso e depois uma solução. As pessoas estão usando métodos confusos e alguns métodos que não funcionam em determinadas situações ou nem sequer funcionam.

Sei que agora é tarde demais, considerando que isso foi publicado há 6 anos, mas espero que futuros visitantes encontrem isso (e espero que possa limpar o código deles e o seu).

Solução simples:

if not @players.include?(p.name) do
  ....
end
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.