How to check if a value is included between two other values? - ruby

I'm trying to express a condition like this:
if 33.75 < degree <= 56.25
# some code
end
But Ruby gives this error:
undefined method `<=' for true:TrueClass
I'm guessing that one way to do it is something like:
if 33.75 < degree and degree <= 56.25
# code
end
But there is no another, easier way?

Ruby also has between?:
if value.between?(lower, higher)

There are many ways of doing the same things in Ruby.
You can check if value is in the range by use of following methods,
14.between?(10,20) # true
(10..20).member?(14) # true
(10..20).include?(14) # true
But, I would suggest using between than member? or include?. You can find more about it here.

You can express a <= x <= b as (a..b).include? x and a <= x < b as (a...b).include? x.
>> (33.75..56.25).include? 33.9
=> true
>> (33.75..56.25).include? 56.25
=> true
>>
>> (33.75..56.25).include? 56.55
=> false
Unfortunately, there seems no such thing for a < x <= b, a < x < b, ..
UPDATE
You can accomplish using (-56.25...-33.75).include? -degree. But it's hard to read. So I recommend you to use 33.75 < degree and degree <= 56.25.

use between? is the easiest way, I found most answers here didn't mention (ruby doc explanation is hard to understand too), using between? does INCLUDE the min and max value.
for example:
irb(main):001:0> 2.between?(1, 3)
=> true
irb(main):002:0> 3.between?(1, 3)
=> true
irb(main):003:0> 1.between?(1, 3)
=> true
irb(main):004:0> 0.between?(1, 3)
=> false
by the way, ruby doc quote:
between?(min, max) → true or false Returns false if obj <=> min is
less than zero or if anObject <=> max is greater than zero, true
otherwise.

undefined method `<=' for true:TrueClass
means that Ruby is not parsing your if-condition the way you expect it.
Using && and adding parentheses helps!
if (33.75<degree) && (degree<=56.25)
...
end
It's a bad habit to leave out parentheses -- as soon as the expression gets more difficult, you could get a surprising outcome. I've seen this many times in other people's code.
Using and instead of && in Ruby is a very bad idea, see:
https://www.tinfoilsecurity.com/blog/ruby-demystified-and-vs
http://rubyinrails.com/2014/01/30/difference-between-and-and-in-ruby/

You can also use this notation:
(1..5) === 3 # => true
(1..5) === 6 # => false

Adjust value to range?
value = 99
[[value,0].max, 5].min # 5
value = -99
[[value,0].max, 5].min # 0
value = 3
[[value,0].max, 5].min # 3

Related

Why does random work like this in Ruby?

I was trying to be clever about deterministically picking random stuff, and found this:
irb(main):011:0> Random.new(Random.new(1).rand + 1).rand == Random.new(1).rand
=> true
irb(main):012:0> Random.new(Random.new(5).rand + 1).rand == Random.new(5).rand
=> false
irb(main):013:0> Random.new(Random.new(5).rand + 5).rand == Random.new(5).rand
=> true
For a second, I thought "wow, maybe that's a property of random number generators", but Python and C# fail to reproduce this.
You’re probably going to be disappointed with this one. Let’s take a look at the output of rand:
irb(main):001:0> Random.rand
0.5739704645347423
It’s a number in the range [0, 1). Random.new accepts an integer seed.
irb(main):002:0> Random.new(5.5) == Random.new(5)
true
Mystery solved!

How do I destructure a range in Ruby?

Is it possible to use destructuring in ruby to extract the end and beginning from a range?
module PriceHelper
def price_range_human( range )
"$%s to $%s" % [range.begin, range.end].map(:number_to_currency)
end
end
I know that I can use array coercion as a really bad hack:
first, *center, last = *rng
"$%s to $%s" % [first, last].map(:number_to_currency)
But is there a syntactical way to get begin and end without actually manually creating an array?
min, max = (1..10)
Would have been awesome.
You can use minmax to destructure ranges:
min, max = (1..10).minmax
min # => 1
max # => 10
If you are using Ruby before 2.7, avoid using this on large ranges.
The beginning and end? I'd use:
foo = 1..2
foo.min # => 1
foo.max # => 2
Trying to use destructuring for a range is a bad idea. Imagine the sizes of the array that could be generated then thrown away, wasting CPU time and memory. It's actually a great way to DOS your own code if your range ends with Float::INFINITY.
end is not the same as max: in 1...10, end is 10, but max is 9
That's because start_val ... end_val is equivalent to start_val .. (end_val - 1):
start_value = 1
end_value = 2
foo = start_value...end_value
foo.end # => 2
foo.max # => 1
foo = start_value..(end_value - 1)
foo.end # => 1
foo.max # => 1
max reflects the reality of the values actually used by Ruby when iterating over the range or testing for inclusion in the range.
In my opinion, end should reflect the actual maximum value that will be considered inside the range, not the value used at the end of the definition of the range, but I doubt that'll change otherwise it'd affect existing code.
... is more confusing and leads to increased maintenance problems so its use is not recommended.
No, Until I am proven incorrect by Cary Swoveland, Weekly World News or another tabloid, I'll continue believing without any evidence that the answer is "no"; but it's easy enough to make.
module RangeWithBounds
refine Range do
def bounds
[self.begin, self.end]
end
end
end
module Test
using RangeWithBounds
r = (1..10)
b, e = *r.bounds
puts "#{b}..#{e}"
end
Then again, I'd just write "#{r.begin.number_to_currency}..#{r.end.number_to_currency}" in the first place.
Amadan's answer is fine. you just need to remove the splat (*) when using it since it is not needed
eg,
> "%s to %s" % (1..3).bounds.map{|x| number_to_currency(x)}
=> "$1.00 to $3.00"

What does .between? method means in Ruby?

I have a exercise of the school and i can't resolve it. Can you help me?
The problem is this:
Try using a method that takes two arguments - use the between? method
to determine if the number 2 lies between the numbers 1 and 3.
I tried to find what is the .between? method but í couldn't find it.
I just know that is a method
The method is Comparable#between?, and you can use it like this:
2.between?(1, 3)
# => true
use between? is the easiest way, I found most answers here didn't mention (ruby doc explanation is hard to understand too), using between? does INCLUDE the min and max value.
for example:
irb(main):001:0> 2.between?(1, 3)
=> true
irb(main):002:0> 3.between?(1, 3)
=> true
irb(main):003:0> 1.between?(1, 3)
=> true
irb(main):004:0> 0.between?(1, 3)
=> false
by the way, ruby doc quote (too hard to understand for newbie):
between?(min, max) → true or false Returns false if obj <=> min is
less than zero or if anObject <=> max is greater than zero, true
otherwise.
From "between" ruby documentation:
between?(min, max) → true or false
Returns false if obj <=> min is less than zero or if anObject <=> max is greater than zero, true otherwise.
Uh oh, and of course, it's #=== method for ranges:
( 1..3 ) === 2 #=> true
( 1..3 ) === 4 #=> false
You can use Range#cover? as a solution :
(1..3).cover? 2 #=> true

How to: Ruby Range that doesn't include the first value

With Ranges in Ruby you can do 0..5 to include all numbers between and including 0 and 5. You can also do 0...5 to include the same numbers except 5 is not included.
(1..5) === 5
=> true
(1...5) === 5
=> false
(1...5) === 4.999999
=> true
Is there a way to exclude the first number instead of the last to get a result like this?
(1...5) === 1
=> false
(1...5) === 1.00000001
=> true
No, there is no built-in support for such a range. You might want to roll your own Range-like class if this behavior is necessary.
Not natively with a Range. You can mess with its mind but you're better off using an incremented first value. This is ugly but:
[(1..5).to_s].map{ |s| a,b=s.split('..').map{|i| i.to_i}; (1+a .. b) } #=> [2..5]
or
Range.new(*[(1..5).to_s].map{ |s| a,b=s.split('..').map{|i| i.to_i}; [1+a,b] }.flatten) #=> 2..5
or
irb(main):004:0> asdf = (1..5)
=> 1..5
irb(main):005:0> Range.new(asdf.min.succ, asdf.max)
=> 2..5
None seem overly elegant.
Besides just sending first_arg.succ instead of first_arg? No, there is no special support for this.
You could monkey patch Range to add a method to behave the way you want. Ex:
class Range
def exclusive()
Range.new(self.first+1, self.last-1)
end
end
(1..5).exclusive === 5
==>false
(1..5) === 5
==>true
Beware of monkeypatching though, as it changes the functionality of existing classes. There is probably a better way to do it in this case, but given the question, this is an acceptable answer.

Ruby: toggle a boolean inline?

How can I get the opposite of a boolean in Ruby (I know that it is converted to 0/1) using a method inline?
say I have the given instance:
class Vote
def return_opposite
self.value
end
end
Which obviously doesn't do anything, but I can't seem to find a method that is simple and short something like opposite() or the like. Does something like this exist and I'm just not looking at the right place in the docs? If one doesn't exist is there a really short ternary that would toggle it from 1 => 0 or 0 => 1?
I like to use this
#object.boolean = !#object.boolean
Boolean expressions are not 0 or 1 in Ruby, actually, 0 is not false
If n is numeric we are swapping 0 and 1...
n == 0 ? 1 : 0 # or...
1 - n # or...
[1, 0][n] # or maybe [1, 0][n & 1] # or...
class Integer; def oh_1; self==0 ? 1:0; end; end; p [12.oh_1, 0.oh_1, 1.oh_1] # or...
n.succ % 2 # or...
n ^= 1
If b already makes sense as a Ruby true or false conditional, it's going to be hard to beat:
!b
These examples differ in how they treat out-of-range input...
You can use XOR operator (exclusive or)
a = true
a # => true
a ^= true
a # => false
a ^= true
a # => true
Edit: See comment by #philomory below.
I believe this is basically an oversight in the boolean classes (TrueClass and FalseClass) in Ruby.
You can negate any object:
nil.! => true
false.! => true
true.! => false
0.! => false
1.! => false
a.! => false (all other objects)
But you cannot in-place negate the boolean objects:
a.!! => does not compile
I guess this would call for trouble with the compiler's grammar.
The best you can do, is thus:
a = a.!
If you just want to access the opposite of the value, use ! as some people have said in the comments. If you want to actually change the value, that would be bool_value = !bool_value. Unless I've misunderstood your question. Which is quite possible.
In order to toggle a boolean data in rails you can do this vote.toggle!(:boolean)
If you want to toggle boolean (that is false and true) , that would be as simple as just use ! as others has stated.
If you want to toggle between 0 and 1 , I can only think of something naive as below :)
def opposite
op = {0=>1,1=>0}
op[self.value]
end
In a Rails app, I use this method to toggle a post between paused and active, so ! (not) is my preferred method.
def toggle
#post = Post.find(params[:id])
#post.update_attributes paused: !#post.paused?
msg = #post.paused? ? 'The post is now paused.' : 'The post is now active.'
redirect_to :back, notice: msg
end
I think that using a ternary can be interesting :
check = false
check == true ? check = false : check = true

Resources