Forum: Ruby <, >, and ranges in a case statement.

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-06-02 11:12
I feel like this should be simple but i can't figure it out.

In a case statement, i know how to use ranges to compare against the
given variable.  But how do i use < or > ?  eg i want to do this:

age = 25

category = case age
  when < 12 : "child"
  when 13..17 : "minor"
  when 18..24 : "young ad*lt"
  when 25..49 : "ad*lt"
  when 50..64 : "middle aged"
  when > 65   : "senior"
  else        : "not an age"
end

(please don't anybody be offended by my age categories, i just made up
this example off the top of my head)

Anyway, the above doesn't work - syntax error.
Neither does this:

when age < 12 : "child"

the test doesn't pass, so if age is eg 10, i get nil back.

Can someone set me straight?
thanks
max

*******************************
postscript - it seems the word 'ad*lt* triggers the spam filter.  hence
the odd wording above.
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-06-02 11:27
Max Williams wrote:
> In a case statement, i know how to use ranges to compare against the
> given variable.  But how do i use < or > ?

Simplest solution is to use a Range with extreme bounds, or use an if
statement (if age < 25 ...).

The long answer is to explain that

  case foo
  when bar
    ...
  end

is syntactic sugar for

  if bar === foo
    ...
  end

So you can get whatever behaviour you like by creating an object which
responds to the === method.

class Bounds
  def initialize(meth,val)
    @meth, @val = meth, val
  end
  def ===(other)
    other.send(@meth, @val)
  end
end
def is(meth,val)
  Bounds.new(meth,val)
end

age = 70
case age
when is(:<,25)
  puts "Youngster"
when is(:>,65)
  puts "Oldie"
end

If you wanted this to be more efficient, you could define constants like

UNDER_25 = is(:<,25)
OVER_65 = is(:>,65)

case age
when UNDER_25
  ... etc
end
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-06-02 11:56
(Received via mailing list)
Attachment: cond.rb (1 KB)
2009/6/2 Brian Candler <b.candler@pobox.com>:
> Max Williams wrote:
>> In a case statement, i know how to use ranges to compare against the
>> given variable.  But how do i use < or > ?

> end
> end
I've attached a similar but more general approach - and a few others as
well.

Kind regards

robert
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-06-02 11:57
Wow, that's a lot more complicated than i thought.  I think for the sake
of ease and readability i'd stick with doing a more longwinded version,
like

category = case
  when age < 12               : "child"
  when (13..17).include? age  : "minor"
  when (18..24).include? age  : "young ad*lt"
  when (25..49).include? age  : "ad*lt"
  when (50..64).include? age  : "middle aged"
  when age > 65               : "senior"
  else                        : "not an age"
end

thanks for the insight though!

cheers
max
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-06-02 12:01
thanks for your in-depth answer robert!  i'll chew over that.  but, in
terms of readability, i think my solution of not passing age into the
block and instead testing it on every line is fine.

thanks a lot though.
max
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-06-02 12:46
Max Williams wrote:
> Wow, that's a lot more complicated than i thought.  I think for the sake
> of ease and readability i'd stick with doing a more longwinded version,
> like
>
> category = case
>   when age < 12               : "child"
>   when (13..17).include? age  : "minor"
>   when (18..24).include? age  : "young ad*lt"
>   when (25..49).include? age  : "ad*lt"
>   when (50..64).include? age  : "middle aged"
>   when age > 65               : "senior"
>   else                        : "not an age"
> end
>
> thanks for the insight though!

If you want to allow for the possibility of fractional ages:

  when (13...18).include? age
  when (18...25).include? age
  when (18...50).include? age
  .. etc
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-06-02 12:53
Good point, thanks :)  i guess you meant (25..50) for the last one :)

cheers!
max
B57c5af36f5c1f33243dd8b2dd9043b1?d=identicon&s=25 F. Senault (Guest)
on 2009-06-02 13:06
(Received via mailing list)
Le 2 juin 2009 à 11:12, Max Williams a écrit :

> category = case age
>   when < 12 : "child"
>   when 13..17 : "minor"
>   when 18..24 : "young ad*lt"
>   when 25..49 : "ad*lt"
>   when 50..64 : "middle aged"
>   when > 65   : "senior"
>   else        : "not an age"
> end

As the others pointed out, there's no easy way to do what you want to.
On the other hand, if you know the bounds of your inputs, your method
isn't bad ; I'd write :

category = case age
  when  0...12  then "child"
  when 12...18  then "minor"
  when 18...25  then "young ad*lt"
  when 25...50  then "ad*lt"
  when 50...65  then "middle aged"
  when 65...999 then "senior"
  else               "not an age"
end

Note that the use of : within if's and case's has been deprecated in
Ruby 1.9 and the next versions.

Fred
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-06-02 13:51
Max Williams wrote:
> Good point, thanks :)  i guess you meant (25..50) for the last one :)

Yeah, you can tell I copy-pasted it from the line above :-)
163755a5d3a5c57bd79c4f41bdda7a22?d=identicon&s=25 Clifford Heath (Guest)
on 2009-06-02 15:27
(Received via mailing list)
Brian Candler wrote:
> Simplest solution is to use a Range with extreme bounds,

... such as a range that ends in Infinity:

65..(1/0.0)
=> 65..Infinity

;-)

Clifford Heath.
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-06-02 15:32
Clifford Heath wrote:
> Brian Candler wrote:
>> Simplest solution is to use a Range with extreme bounds,
>
> ... such as a range that ends in Infinity:
>
> 65..(1/0.0)
> => 65..Infinity
>
> ;-)
>
> Clifford Heath.
haha, i thought about that but it seemed kind of crazy.  It surprises me
a little that Infinity isn't a singleton class like NilClass in ruby.
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-06-02 15:34
>> Brian Candler wrote:

>> 65..(1/0.0)
>> => 65..Infinity

> haha, i thought about that but it seemed kind of crazy.  It surprises me
> a little that Infinity isn't a singleton class like NilClass in ruby.
D1f1c20467562fc1d8c8aa0d328def62?d=identicon&s=25 Florian Gilcher (skade)
on 2009-06-02 15:48
(Received via mailing list)
On Jun 2, 2009, at 3:32 PM, Max Williams wrote:

>>
>> Clifford Heath.
> haha, i thought about that but it seemed kind of crazy.  It
> surprises me
> a little that Infinity isn't a singleton class like NilClass in ruby.


I guess that is because there are actually 2 infinities and both are
valid
values with well-defined operations in IEEE754.

Regards,
Florian

--
Florian Gilcher

smtp:   flo@andersground.net
jabber: Skade@jabber.ccc.de
gpg:    533148E2
134ea397777886d6f0aa992672a50eaa?d=identicon&s=25 Mark Thomas (Guest)
on 2009-06-02 21:23
(Received via mailing list)
On Jun 2, 9:32 am, Max Williams <toastkid.willi...@gmail.com> wrote:
> Clifford Heath wrote:
> > Brian Candler wrote:
> >> Simplest solution is to use a Range with extreme bounds,
>
> > ... such as a range that ends in Infinity:
>
> > 65..(1/0.0)
> > => 65..Infinity

Interesting... you can assign it to a constant.

Infinity = 1/0.0

Then you can use it in ranges:

(-Infinity..0).include? 100000
=> false
(0..Infinity).include? 100000
=> true
08995c0e987a0b6d452a791369f96370?d=identicon&s=25 Alex (Guest)
on 2009-06-02 21:27
(Received via mailing list)
That's an interesting idea.. I can see an opportunity for a great deal
of
abuse there, as well.
It would certainly be cool to write my infinite loops like:

(0..Infinity).each {|d| ... }


Alex
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-06-02 23:29
By the way, this is a real good way to lock up your cpu, i just
discovered :)

infinity = 1.0/0
(0..infinity).to_a

grrrrrrriiiiiiinnnnnnnddddddddd
This topic is locked and can not be replied to.