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.

Odpowiedzi:


306
if i. between? (1, 10)
  zrób rzecz 1 
elsif i.between? (11,20)
  zrób coś 2 
...

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

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

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

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



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.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.