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
Tyler DeWitt
fonte
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)

dizzy42
fonte
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.

Bozhidar Batsov
fonte
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 && [email protected]?(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
ilasno
fonte
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
Sagar Pandya
fonte
7
module Enumerable
  def does_not_include?(item)
    !include?(item)
  end
end

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

Jesse Wolgamott
fonte
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
2

Use unless:

unless @players.include?(p.name) do
  ...
end
Mikita Belahlazau
fonte
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.

tekuri
fonte
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

MeWillWork4Food
fonte
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
ckshei
fonte
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.

KarmaDeli
fonte
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
Voidableryzer
fonte