Determinando se uma variável está dentro do intervalo?

134

Eu preciso escrever um loop que faz algo como:

if i (1..10)
  do thing 1
elsif i (11..20)
  do thing 2
elsif i (21..30)
  do thing 3
etc...

Até agora, porém, seguimos os caminhos errados em termos de sintaxe.

btw
fonte

Respostas:

306
se i.entre? (1, 10)
  fazer coisa 1 
(11,20)
  faça a coisa 2 
...
rogerdpack
fonte
3
Isso também funciona para Datee DateTimeobjetos, enquanto ===não funciona.
Aditya
i.between?(1..10)não vai funcionar (se for ..) Suponho que deve haver uma razão para isso
nonopolarity
entre? precisaria de dois parâmetros que não permitiriam alcance.
Manish Nagdewani
5
é inclusivo ou exclusivo?
precisa saber é o seguinte
1
@andrewcockerham Inclusive. 3.between?(1, 3) => true
Tyler James Young
84

Use o ===operador (ou seu sinônimo include?)

if (1..10) === i
Baldu
fonte
1
Tem a agradável vantagem de também trabalhar com isendo algo mais do que um número (como nil)
Christoffer Klang
4
Não seria uma solução muito eficiente se o intervalo tivesse sido significativamente grande.
Rthbound # 25/13
6
Para futuro leitor, a forma alternativa if i === (1..10)não funcionará
Anwar
@rthbound, por quê? (1..10000000000000000) não é uma matriz. (1..10000000000000000) === 5000000000000000está apenas fazendo um "entre" teste sob o capô
John La Rooy
1
@ Anwar, você poderia explicar por que não funciona da outra maneira?
Govind Rai
70

Como o @Baldu disse, use o operador === ou caso de uso / quando o qual usar internamente ===:

case i
when 1..10
  # do thing 1
when 11..20
  # do thing 2
when 21..30
  # do thing 3
etc...
Vincent Robert
fonte
de todas as respostas, esse também é provavelmente o melhor desempenho quando você tem vários intervalos.
xentek
40

se você ainda queria usar intervalos ...

def foo(x)
 if (1..10).include?(x)
   puts "1 to 10"
 elsif (11..20).include?(x)
   puts "11 to 20"
 end
end
Tim Hoolihan
fonte
8

Geralmente, você pode obter um desempenho muito melhor com algo como:

if i >= 21
  # do thing 3
elsif i >= 11
  # do thing 2
elsif i >= 1
  # do thing 1
Brad Werth
fonte
8

Você poderia usar
if (1..10).cover? i then thing_1 elsif (11..20).cover? i then thing_2

e de acordo com essa referência no Fast Ruby é mais rápido queinclude?

Juan Felipe Rodriguez
fonte
Na verdade, é muito mais rápido
Joe Half Face
5

Não é uma resposta direta à pergunta, mas se você quiser o contrário de "dentro":

(2..5).exclude?(7)

verdade

Estrangeiro companheiro
fonte
Note que exclude?é uma adição ao Rails .
Jan Klimo
1

Uma resposta mais dinâmica, que pode ser construída em Ruby:

def select_f_from(collection, point) 
  collection.each do |cutoff, f|
    if point <= cutoff
      return f
    end
  end
  return nil
end

def foo(x)
  collection = [ [ 0, nil ],
                 [ 10, lambda { puts "doing thing 1"} ],
                 [ 20, lambda { puts "doing thing 2"} ],
                 [ 30, lambda { puts "doing thing 3"} ],
                 [ 40, nil ] ]

  f = select_f_from(collection, x)
  f.call if f
end

Portanto, neste caso, os "intervalos" são realmente limitados a zero para capturar as condições de contorno.

m104
fonte
-2

Para cordas:

(["GRACE", "WEEKLY", "DAILY5"]).include?("GRACE")

# => true

vidur punj
fonte