# Case

Hi

a=3
p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 3, a>5 then 3
else 99
end

Seems you can't combine values and statements (a>5).
How can I write that, if I have additional statements (in some cases), but would like to use "values only" for most of the cases?

Thanks
Opti

There's no such thing as a statement in Ruby.

···

On Tue, Jan 10, 2017 at 4:16 PM, Die Optimisten <inform@die-optimisten.net> wrote:

Seems you can't combine values and statements (a>5).

--
Eric Christopherson

You can use a lambda if you like:

irb(main):032:0> (0..10).each do |a|
irb(main):033:1* p case a
irb(main):034:2> when 0 then 0
irb(main):035:2> when 1 then 1
irb(main):036:2> when 2 then 2
irb(main):037:2> when -> (x) { x == 3 || x > 5 } then 3
irb(main):038:2> else 99
irb(main):039:2> end
irb(main):040:1> end
0
1
2
3
99
99
3
3
3
3
3
=> 0..10

Hope this helps,

Mike

···

On Jan 10, 2017, at 5:16 PM, Die Optimisten <inform@die-optimisten.net> wrote:

Hi

a=3
p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 3, a>5 then 3
else 99
end

Seems you can't combine values and statements (a>5).
How can I write that, if I have additional statements (in some cases), but would like to use "values only" for most of the cases?

Thanks
Opti

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

a=3
p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 3, a>5 then 3
else 99
end

a=3
p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 4..5 then 99 # using a range here to cover your original 'else'
clause
else 3 # this is now 'when 3, a > 5'
end

And the generic answer for arbitrary conditions is: use a lambda,
because my suggestion to make lambda support #=== as an alias for
#call and #[] was implemented a long time ago:

irb(main):002:0> x = lambda {|a| a > 5}
=> #<Proc:0x00000001287250@(irb):2 (lambda)>
irb(main):003:0> 10.times {|i| printf "%2d -> %p\n", i, x === i}
0 -> false
1 -> false
2 -> false
3 -> false
4 -> false
5 -> false
6 -> true
7 -> true
8 -> true
9 -> true
=> 10

Equipped with the knowledge that case uses === for matching you can
easily use that here:

LARGER_THAN_5 = lambda {|n| n > 5}

a=3
p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 3, LARGER_THAN_5 then 3
else 99
end

Note, you can rewrite that to

a = 3
p case a
when 0,1,2,3 then a
when LARGER_THAN_5 then 3
else 99
end

or use a Hash or ...

irb(main):047:0> FIXED = {0=>0,1=>1,2=>2,3=>3}
irb(main):048:0> -3.upto(10) {|i| printf "%2d -> %p\n", i,
FIXED.fetch(i) { i>5 ? 3 : 99 }}
-3 -> 99
-2 -> 99
-1 -> 99
0 -> 0
1 -> 1
2 -> 2
3 -> 3
4 -> 99
5 -> 99
6 -> 3
7 -> 3
8 -> 3
9 -> 3
10 -> 3
=> -3

etc.

Cheers

robert

···

On Wed, Jan 11, 2017 at 12:10 AM, James Pacheco <james.pacheco@gmail.com> wrote:

a=3
p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 3, a>5 then 3
else 99
end

a=3
p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 4..5 then 99 # using a range here to cover your original 'else'
clause
else 3 # this is now 'when 3, a > 5'
end

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/

p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 3, a>5 then 3
else 99
end

try the else part,

p case a
when 0 then 0
when 1 then 1
when 2 then 2
when 3 then 3
else
if a > 5
3
else
99
end
end

you can replace the if with another (nested) case if you're fond of case : )

Seems you can't combine values and statements (a>5)

try the other case and other combinations case w case, case w if, etc,

p case
when [0,1,2,3].include?(a)
a
when a > 5
3
else
99
end

kind regards
--botp

···

On Wed, Jan 11, 2017 at 6:16 AM, Die Optimisten <inform@die-optimisten.net> wrote:

And the generic answer for arbitrary conditions is: use a lambda,
because my suggestion to make lambda support #=== as an alias for
#call and #[] was implemented a long time ago:

As the great Alan Perlis didn't quite say:

[Ruby] programmers know the value of everything and the cost of nothing.

Generic answers are great for generic questions, but using a proc in this case (no pun intended) comes with a very large cost. I really liked James' suggestion, to flip the logic around, but I knew that the range was

What I'm truly surprised by is James' solution being as slow as it was. I figured it had to beat out proc activation. I'm also a bit surprised at the cost of my valueless case (ryan2).

---- benchmark and results follow

require 'benchmark/ips'

LARGER_THAN_5 = lambda { |m| m > 5}

def robert n
case n
when 0 then 0
when 1 then 1
when 2 then 2
when 3, LARGER_THAN_5 then 3
else 99
end
end

def robert2 n
case n
when 0,1,2,3 then n
when LARGER_THAN_5 then 3
else 99
end
end

def mike n
case n
when 0 then 0
when 1 then 1
when 2 then 2
when -> (x) { x == 3 || x > 5 } then 3
else 99
end
end

def james n
case n
when 0 then 0
when 1 then 1
when 2 then 2
when 4..5 then 99 # using a range here to cover your original 'else' clause
else 3 # this is now 'when 3, a > 5'
end
end

def ryan n
case n
when 0 then 0
when 1 then 1
when 2 then 2
when 4, 5 then 99 # because range will bite you
else 3
end
end

def ryan2 n
case
when n==0 then 0
when n==1 then 1
when n==2 then 2
when n==3 || n>5 then 3 # just to see the impact of a valueless case
else 99
end
end

10.times do |n|
v0, v1, v2, v3, v4, v5 =
robert(n), robert2(n), mike(n), james(n), ryan(n), ryan2(n)

abort "bad" if [v0, v1, v2, v3, v4, v5].uniq.size != 1
end

Benchmark.ips do |x|
x.report("robert") do |t| t.times do 10.times do |n| robert n end end end
x.report("robert2") do |t| t.times do 10.times do |n| robert2 n end end end
x.report("james") do |t| t.times do 10.times do |n| james n end end end
x.report("mike") do |t| t.times do 10.times do |n| mike n end end end
x.report("ryan") do |t| t.times do 10.times do |n| ryan n end end end
x.report("ryan2") do |t| t.times do 10.times do |n| ryan2 n end end end

x.compare!
end

# Calculating -------------------------------------
# robert 278.388k (+/- 2.8%) i/s - 1.408M in 5.059990s
# robert2 283.350k (+/- 2.4%) i/s - 1.425M in 5.031756s
# james 264.979k (+/- 3.3%) i/s - 1.344M in 5.079088s
# mike 139.618k (+/- 3.8%) i/s - 701.028k in 5.029633s
# ryan 849.322k (+/- 3.0%) i/s - 4.300M in 5.067430s
# ryan2 640.050k (+/- 2.5%) i/s - 3.209M in 5.016532s

···

On Jan 11, 2017, at 03:27, Robert Klemme <shortcutter@googlemail.com> wrote:

#
# Comparison:
# ryan: 849322.2 i/s
# ryan2: 640050.3 i/s - 1.33x slower
# robert2: 283349.9 i/s - 3.00x slower
# robert: 278387.7 i/s - 3.05x slower
# james: 264979.4 i/s - 3.21x slower
# mike: 139618.4 i/s - 6.08x slower

First time I hear about that alias.
Just awesome! Thank you very much.

···

On Wed, 11 Jan 2017 at 11:27, Robert Klemme <shortcutter@googlemail.com> wrote:

On Wed, Jan 11, 2017 at 12:10 AM, James Pacheco <james.pacheco@gmail.com> > wrote:

>> a=3

>> p case a

>> when 0 then 0

>> when 1 then 1

>> when 2 then 2

>> when 3, a>5 then 3

>> else 99

>> end

>

> a=3

> p case a

> when 0 then 0

> when 1 then 1

> when 2 then 2

> when 4..5 then 99 # using a range here to cover your original 'else'

> clause

> else 3 # this is now 'when 3, a > 5'

> end

And the generic answer for arbitrary conditions is: use a lambda,

because my suggestion to make lambda support #=== as an alias for

#call and #[] was implemented a long time ago:

irb(main):002:0> x = lambda {|a| a > 5}

=> #<Proc:0x00000001287250@(irb):2 (lambda)>

irb(main):003:0> 10.times {|i| printf "%2d -> %p\n", i, x === i}

0 -> false

1 -> false

2 -> false

3 -> false

4 -> false

5 -> false

6 -> true

7 -> true

8 -> true

9 -> true

=> 10

Equipped with the knowledge that case uses === for matching you can

easily use that here:

LARGER_THAN_5 = lambda {|n| n > 5}

a=3

p case a

when 0 then 0

when 1 then 1

when 2 then 2

when 3, LARGER_THAN_5 then 3

else 99

end

Note, you can rewrite that to

a = 3

p case a

when 0,1,2,3 then a

when LARGER_THAN_5 then 3

else 99

end

or use a Hash or ...

irb(main):047:0> FIXED = {0=>0,1=>1,2=>2,3=>3}

irb(main):048:0> -3.upto(10) {|i| printf "%2d -> %p\n", i,

FIXED.fetch(i) { i>5 ? 3 : 99 }}

-3 -> 99

-2 -> 99

-1 -> 99

0 -> 0

1 -> 1

2 -> 2

3 -> 3

4 -> 99

5 -> 99

6 -> 3

7 -> 3

8 -> 3

9 -> 3

10 -> 3

=> -3

etc.

Cheers

robert

--

[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can

- without end}

http://blog.rubybestpractices.com/

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

That is so cool Robert!

Thanks for the insight Ryan. I was expecting that. It doesn't take the
value out of the === alias tough.
Although I must admite it may decrease code readability. It needs to be
used in a wise way.

···

On Wed, 11 Jan 2017 at 12:30, Ryan Davis <ryand-ruby@zenspider.com> wrote:

> On Jan 11, 2017, at 03:27, Robert Klemme <shortcutter@googlemail.com> > wrote:

>

> And the generic answer for arbitrary conditions is: use a lambda,

> because my suggestion to make lambda support #=== as an alias for

> #call and #[] was implemented a long time ago:

As the great Alan Perlis didn't quite say:

> [Ruby] programmers know the value of everything and the cost of nothing.

Generic answers are great for generic questions, but using a proc in this
case (no pun intended) comes with a very large cost. I really liked James'
suggestion, to flip the logic around, but I knew that the range was

What I'm truly surprised by is James' solution being as slow as it was. I
figured it had to beat out proc activation. I'm also a bit surprised at the
cost of my valueless case (ryan2).

---- benchmark and results follow

require 'benchmark/ips'

LARGER_THAN_5 = lambda { |m| m > 5}

def robert n

case n

when 0 then 0

when 1 then 1

when 2 then 2

when 3, LARGER_THAN_5 then 3

else 99

end

end

def robert2 n

case n

when 0,1,2,3 then n

when LARGER_THAN_5 then 3

else 99

end

end

def mike n

case n

when 0 then 0

when 1 then 1

when 2 then 2

when -> (x) { x == 3 || x > 5 } then 3

else 99

end

end

def james n

case n

when 0 then 0

when 1 then 1

when 2 then 2

when 4..5 then 99 # using a range here to cover your original 'else'
clause

else 3 # this is now 'when 3, a > 5'

end

end

def ryan n

case n

when 0 then 0

when 1 then 1

when 2 then 2

when 4, 5 then 99 # because range will bite you

else 3

end

end

def ryan2 n

case

when n==0 then 0

when n==1 then 1

when n==2 then 2

when n==3 || n>5 then 3 # just to see the impact of a valueless case

else 99

end

end

10.times do |n|

v0, v1, v2, v3, v4, v5 =

robert(n), robert2(n), mike(n), james(n), ryan(n), ryan2(n)

abort "bad" if [v0, v1, v2, v3, v4, v5].uniq.size != 1

end

Benchmark.ips do |x|

x.report("robert") do |t| t.times do 10.times do |n| robert n end end
end

x.report("robert2") do |t| t.times do 10.times do |n| robert2 n end end
end

x.report("james") do |t| t.times do 10.times do |n| james n end end
end

x.report("mike") do |t| t.times do 10.times do |n| mike n end end
end

x.report("ryan") do |t| t.times do 10.times do |n| ryan n end end
end

x.report("ryan2") do |t| t.times do 10.times do |n| ryan2 n end end
end

x.compare!

end

# Calculating -------------------------------------

# robert 278.388k (+/- 2.8%) i/s - 1.408M in
5.059990s

# robert2 283.350k (+/- 2.4%) i/s - 1.425M in
5.031756s

# james 264.979k (+/- 3.3%) i/s - 1.344M in
5.079088s

# mike 139.618k (+/- 3.8%) i/s - 701.028k in
5.029633s

# ryan 849.322k (+/- 3.0%) i/s - 4.300M in
5.067430s

# ryan2 640.050k (+/- 2.5%) i/s - 3.209M in
5.016532s

#

# Comparison:

# ryan: 849322.2 i/s

# ryan2: 640050.3 i/s - 1.33x slower

# robert2: 283349.9 i/s - 3.00x slower

# robert: 278387.7 i/s - 3.05x slower

# james: 264979.4 i/s - 3.21x slower

# mike: 139618.4 i/s - 6.08x slower

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

> p case a

> when 0 then 0

> when 1 then 1

> when 2 then 2

> when 3, a>5 then 3

> else 99

> end

try the else part,

p case a

when 0 then 0

when 1 then 1

when 2 then 2

when 3 then 3

else

if a > 5

3

else

99

end

end

you can replace the if with another (nested) case if you're fond of case :
)

> Seems you can't combine values and statements (a>5)

try the other case and other combinations case w case, case w if, etc,

p case

when [0,1,2,3].include?(a)

a

when a > 5

3

else

99

end

kind regards

--botp

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

···

On Wed, 11 Jan 2017 at 13:07, botp <botpena@gmail.com> wrote:

On Wed, Jan 11, 2017 at 6:16 AM, Die Optimisten > > <inform@die-optimisten.net> wrote:

And the generic answer for arbitrary conditions is: use a lambda,
because my suggestion to make lambda support #=== as an alias for
#call and #[] was implemented a long time ago:

As the great Alan Perlis didn't quite say:

[Ruby] programmers know the value of everything and the cost of nothing.

Generic answers are great for generic questions, but using a proc in this case (no pun intended) comes with a very large cost. I really liked James' suggestion, to flip the logic around, but I knew that the range was

I wasn't suggesting to use the lambda here - I was just using this
case for illustration. For other cases you can actually create pretty

What I'm truly surprised by is James' solution being as slow as it was. I figured it had to beat out proc activation. I'm also a bit surprised at the cost of my valueless case (ryan2).

I believe James' solution creates a new Range instance during every
iteration (unless there is some optimization going un underneath like
for Regex) so you could try with the range in a constant.

Kind regards

robert

···

On Wed, Jan 11, 2017 at 1:30 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:

On Jan 11, 2017, at 03:27, Robert Klemme <shortcutter@googlemail.com> wrote:

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/

What I'm truly surprised by is James' solution being as slow as it was. I figured it had to beat out proc activation. I'm also a bit surprised at the cost of my valueless case (ryan2).

<snip>

def ryan n
case n
when 0 then 0
when 1 then 1
when 2 then 2
when 4, 5 then 99 # because range will bite you
else 3
end
end

All literals for "when" means MRI/YARV optimizes the above to a
hash table internally ("opt_case_dispatch" in compile.c and insns.def)

def ryan2 n
case
when n==0 then 0
when n==1 then 1
when n==2 then 2
when n==3 || n>5 then 3 # just to see the impact of a valueless case
else 99
end
end

No optimized dispatch, above, since it's all variable.

···

Ryan Davis <ryand-ruby@zenspider.com> wrote:

# Calculating -------------------------------------
# robert 278.388k (+/- 2.8%) i/s - 1.408M in 5.059990s
# robert2 283.350k (+/- 2.4%) i/s - 1.425M in 5.031756s
# james 264.979k (+/- 3.3%) i/s - 1.344M in 5.079088s
# mike 139.618k (+/- 3.8%) i/s - 701.028k in 5.029633s
# ryan 849.322k (+/- 3.0%) i/s - 4.300M in 5.067430s
# ryan2 640.050k (+/- 2.5%) i/s - 3.209M in 5.016532s
#
# Comparison:
# ryan: 849322.2 i/s
# ryan2: 640050.3 i/s - 1.33x slower
# robert2: 283349.9 i/s - 3.00x slower
# robert: 278387.7 i/s - 3.05x slower
# james: 264979.4 i/s - 3.21x slower
# mike: 139618.4 i/s - 6.08x slower

(0..3) is a range. it will include any numbers (including fractions etc) in bw

(0..3).include? 1.5
=> true

kind regards
--botp

···

On Wed, Jan 11, 2017 at 9:22 PM, Daniel Ferreira <subtileos@gmail.com> wrote:

It's because (a..b).include?(n) checks if n >= a && n <= b. It does not
check if the value is actually inside of the range.

···

On Wed, Jan 11, 2017 at 9:43 AM, botp <botpena@gmail.com> wrote:

On Wed, Jan 11, 2017 at 9:22 PM, Daniel Ferreira <subtileos@gmail.com> > wrote:

(0..3) is a range. it will include any numbers (including fractions etc)
in bw

(0..3).include? 1.5
=> true

kind regards
--botp

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

That is surprising.
I had this behaviour in my mind:

(0..3).each { |i| puts I }
0
1
2
3

Different behaviours?

···

On Wed, 11 Jan 2017 at 14:47, Eli Sadoff <snood1205@gmail.com> wrote:

It's because (a..b).include?(n) checks if n >= a && n <= b. It does not
check if the value is actually inside of the range.

On Wed, Jan 11, 2017 at 9:43 AM, botp <botpena@gmail.com> wrote:

On Wed, Jan 11, 2017 at 9:22 PM, Daniel Ferreira <subtileos@gmail.com> > wrote:

(0..3) is a range. it will include any numbers (including fractions etc)
in bw

(0..3).include? 1.5

=> true

kind regards

--botp

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

That is surprising.
I had this behaviour in my mind:

(0..3).each { |i| puts I }
0
1
2
3

> (0..3).to_a
=> [0, 1, 2, 3]
Different behaviours?

It's because (a..b).include?(n) checks if n >= a && n <= b. It does not
check if the value is actually inside of the range.

(0..3) is a range. it will include any numbers (including fractions etc)
in bw

(0..3).include? 1.5

=> true

kind regards

--botp

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

···

On Wed, 11 Jan 2017 at 15:11, Daniel Ferreira <subtileos@gmail.com> wrote:

On Wed, 11 Jan 2017 at 14:47, Eli Sadoff <snood1205@gmail.com> wrote:
On Wed, Jan 11, 2017 at 9:43 AM, botp <botpena@gmail.com> wrote:
On Wed, Jan 11, 2017 at 9:22 PM, Daniel Ferreira <subtileos@gmail.com> > wrote:

That is surprising.
I had this behaviour in my mind:

(0..3).each { |i| puts I }
0
1
2
3

> (0..3).to_a
=> [0, 1, 2, 3]

Different behaviours?

Also documentation neglects completely that behaviour. A reader will
hardly get it.
I believe we should update Range#include? documentation with those
particular situations.
Are there unit tests for that as well?

It's because (a..b).include?(n) checks if n >= a && n <= b. It does not
check if the value is actually inside of the range.

(0..3) is a range. it will include any numbers (including fractions etc)
in bw

(0..3).include? 1.5

=> true

kind regards

--botp

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>

···

On Wed, 11 Jan 2017 at 15:13, Daniel Ferreira <subtileos@gmail.com> wrote:

On Wed, 11 Jan 2017 at 15:11, Daniel Ferreira <subtileos@gmail.com> wrote:
On Wed, 11 Jan 2017 at 14:47, Eli Sadoff <snood1205@gmail.com> wrote:
On Wed, Jan 11, 2017 at 9:43 AM, botp <botpena@gmail.com> wrote:
On Wed, Jan 11, 2017 at 9:22 PM, Daniel Ferreira <subtileos@gmail.com> > wrote:

Hi all!
- in 2 days as much conversation as in many months!!
...don't know when I'm through with all!

Opti :))

(0..3).each { |i| puts I }
0
1
2
3

> (0..3).to_a
=> [0, 1, 2, 3]

ruby tries very hard to iterate as much as it can. you would not want
it to spit out all/infinite numbers.
eg, if you feed a float for the first obj of the range, ruby will raise,

(1.0 .. 3).each{|x| p x}

TypeError: can't iterate from Float

if the only the last obj is float, ruby will try to be friendly again.
eg

(0 .. 3.5).each{|x| p x}

0
1
2
3

you can also try the #step method.
eg

(1.1 .. 2.03).step(0.1).to_a

=> [1.1, 1.2000000000000002, 1.3, 1.4000000000000001, 1.5, 1.6,
1.7000000000000002, 1.8000000000000003, 1.9000000000000001, 2.0]

again, ruby just trying to help programmer.

kind regards
--botp

···

On Wed, Jan 11, 2017 at 11:13 PM, Daniel Ferreira <subtileos@gmail.com> wrote:

On the whole if the behavior of something seems surprising, it is either
likely documented or is definitely in the source code.

···

On Wed, Jan 11, 2017 at 12:11 PM, botp <botpena@gmail.com> wrote:

On Wed, Jan 11, 2017 at 11:13 PM, Daniel Ferreira <subtileos@gmail.com> > wrote:
>> (0..3).each { |i| puts I }
>> 0
>> 1
>> 2
>> 3

>> > (0..3).to_a
>> => [0, 1, 2, 3]

ruby tries very hard to iterate as much as it can. you would not want
it to spit out all/infinite numbers.
eg, if you feed a float for the first obj of the range, ruby will raise,

> (1.0 .. 3).each{|x| p x}
TypeError: can't iterate from Float

if the only the last obj is float, ruby will try to be friendly again.
eg

> (0 .. 3.5).each{|x| p x}
0
1
2
3

you can also try the #step method.
eg

> (1.1 .. 2.03).step(0.1).to_a
=> [1.1, 1.2000000000000002, 1.3, 1.4000000000000001, 1.5, 1.6,
1.7000000000000002, 1.8000000000000003, 1.9000000000000001, 2.0]

again, ruby just trying to help programmer.

kind regards
--botp

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>