Ustalanie, czy zmienna mieści się w zakresie?

134

Muszę napisać pętlę, która robi coś takiego:

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

Ale do tej pory poszli złymi ścieżkami pod względem składni.

przy okazji
źródło

Odpowiedzi:

306
if i. between? (1, 10)
  zrób rzecz 1 
elsif i.between? (11,20)
  zrób coś 2 
...
rogerdpack
źródło
3
Działa to również w przypadku obiektów Datei, DateTimepodczas gdy ===nie.
Aditya
i.between?(1..10)nie zadziała (jeśli jest ..) Przypuszczam, że musi być ku temu powód
niepolarność
pomiędzy? wymagałby dwóch parametrów, nie pozwoliłby na zakres.
Manish Nagdewani
5
czy jest inkluzywny czy ekskluzywny?
andrewcockerham
1
@andrewcockerham Inclusive. 3.between?(1, 3) => true
Tyler James Young
84

Użyj ===operatora (lub jego synonimu include?)

if (1..10) === i
Baldu
źródło
1
Ma tę zaletę, że pracuje się z ikimś innym niż liczba (na przykład nil)
Christoffer Klang,
4
Nie wydawałoby się bardzo wydajnym rozwiązaniem, gdyby zasięg był znacznie duży.
rthbound
6
Dla przyszłego czytelnika alternatywny sposób if i === (1..10)nie zadziała
Anwar
@rthbound, dlaczego? (1..10000000000000000) nie jest tablicą. (1..10000000000000000) === 5000000000000000robi tylko test „pomiędzy” pod maską
John La Rooy,
1
@Anwar czy możesz wyjaśnić, dlaczego to nie działa w drugą stronę?
Govind Rai
70

Jak powiedział @Baldu, użyj operatora === lub przypadku użycia / kiedy wewnętrznie używa ===:

case i
when 1..10
  # do thing 1
when 11..20
  # do thing 2
when 21..30
  # do thing 3
etc...
Vincent Robert
źródło
spośród wszystkich odpowiedzi jest to prawdopodobnie najbardziej wydajne rozwiązanie, gdy masz wiele zakresów.
xentek
40

jeśli nadal chcesz używać zakresów ...

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
źródło
8

Zwykle można uzyskać znacznie lepszą wydajność, stosując coś takiego:

if i >= 21
  # do thing 3
elsif i >= 11
  # do thing 2
elsif i >= 1
  # do thing 1
Brad Werth
źródło
8

Możesz użyć
if (1..10).cover? i then thing_1 elsif (11..20).cover? i then thing_2

i według tego testu w Fast Ruby jest szybszy niżinclude?

Juan Felipe Rodriguez
źródło
To jest o wiele szybsze
Joe Half Face
5

Nie jest to bezpośrednia odpowiedź na pytanie, ale jeśli wolisz coś przeciwnego do „wewnątrz”:

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

prawdziwe

Kolega nieznajomy
źródło
Zauważ, że exclude?jest to dodatek do Railsów .
Jan Klimo
1

Bardziej dynamiczna odpowiedź, którą można zbudować w Rubim:

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

Tak więc w tym przypadku „zakresy” są tak naprawdę ogrodzone zerami, aby uchwycić warunki brzegowe.

m104
źródło
-2

Na smyczki:

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

# => prawda

vidur punj
źródło