Is true && true == false? - ruby

Am I missing something or is this a bug in ruby?
a = %w(foo bar baz)
a.include? "foo" # => true
a.size == 3 # => true
a.include? "foo" && a.size == 3 # => false

a.include? "foo" && a.size == 3
is evaluated as
a.include? ("foo" && a.size == 3)
and because
"foo" && a.size == 3 #=> true
this is equivalent to
a.include? true
which is false

Is true && true == false?
No.
irb(main):003:0> true && true == false
=> false

What you meant to check is
a.include?("foo") && a.size == 3
Your condition is checking if "foo" && a.size == 3 (which is true because "foo" is neither nil nor false) is included in the array.
The solution of Zack's comment is correct too, but looking a bit unusual:
(a.include? "foo") && a.size == 3
One reason why the whole expression is considered the method's argument in case of missing parentheses is you can do:
puts 3 + 4 * 5 - 6

Related

Why does expression (true == true == true) produce a syntax error?

Ruby:
true == true == true
syntax error, unexpected tEQ
vs. JavaScript:
true == true == true
// => true
vs. C:
1 == 1 == 1
// => 1
Association direction, which controls the order of operators having their arguments evaluated, is not defined for the == method, same as for ===, !=, =~ and <=> methods as well (all of which have the same precedence and form a separate precedence group exclusively).
Documentation
Thus evaluation order in case of multiple operators from the list mentioned above being chained in a row should be set explicitly via either
parenthesis ():
(true == true) == true # => true
true == (true == true) # => true
or dot operator . (can be omitted for the last equality check in a row):
true .== true == true # => true
TL;DR The syntax implies that all 3 values are equal this is not what it does in javascript or C, so by ruby giving a syntax error the door is open for this to be implemented in the future.
If I understand the question correctly value_a == value_b == value_c should only return true if they are all equal using == as the comparison operater as shown in this method
# version 1
def compare_3_values(a, b, c)
a == b && a == c && b == c
end
there is another possible expected outcome though. to implement this as shown in the previous answer:
#version 2
def compare_3_values(a, b, c)
(a == b) == c
end
The results are worlds apart.
JavaScript always uses version 2 which is pretty useless as the 3rd item is always being compared against true or false (0 or 1 if the 3rd item is an integer) that's why false == false == true returns true.
The good news is that because ruby gives a syntax error it's the only language that can implement this without breaking everyone's code.
for any other language it would break so much code that even if it were implemented in a later major version there would need to be a flag/setting to turn this on or off for years to come, hence it will never be worthwhile.
Some interesting results in Ruby
false .== false == true
=> true
false .== true == false
=> true
true .== false == false
=> true
false .== false == false
=> false
true .== true == false
false
And in javascript
false == false == true
=> true
false == true == false
=> true
true == false == false
=> true
false == false == false
=> false
true == true == false
=> false
Edit tested in C as well, acts similar to JavaScript in that it compares the result of the first two values against the third value
The first answer is excellent, but just in case it's not completely clear (and people asking why), here are few more examples.
In C, the == operator is left-to-right associative and boolean is represented as 1 (true) and 0 (false), so the first 1 == 1 evaluates to 1 (true) and then you are evaluating the result of first expression with the second. You can try:
2 == 2 == 2 // => 0
Which in C, is evaluated as:
(2 == 2) == 2
1 == 2 // => 0
In Javascript, similarly to C, == is left to right associative. Let's try with 0 this time (although the same example from C would work as well):
0 == 0 == 0
false
Again:
0 == 0 == 0
true == 0 // => false
In Ruby == does not have associative properties, ie. it can't be used multiple times in single expression, so that expression can't be evaluated. Why that decision was made is a question for the author of the language. Further, Ruby doesn't define numeric 1 as a boolean, so 1 == true evaluates to false.
The second answer states there are some "weird" cases in Ruby, but they all evaluate as expected:
(1 == 1) == 1
true == 1 # => false
1 == (1 == 1)
1 == true # => false
1 .== 1 == 1
(1 == 1) == 1
true == 1 # => false
false .== false == true
(false == false) == true
true == true # => true
false .== true == false
(false == true) == false
false == false # => true
true .== false == false
(true == false) == false
false == false # => true
false .== false == false
(false == false) == false
true == false # => false
true .== true == false
(true == true) == false
true == false # => false

Is there a better way to compare strings in a reasonable amount of time?

I have this Ruby function that tells me if two strings are "almost" equal, that is, if all characters in the string are identical and ordered in the same way except for one. So for instance, these are equal
equal
eual
but these are not
eal
equal
(two characters are missing in the above). So with help, I have come up with this
(lcs(a,b) == shortest && longest.length - shortest.length == 1)
in which las is defined by
def lcs(xstr, ystr)
return "" if xstr.empty? || ystr.empty?
x, xs, y, ys = xstr[0..0], xstr[1..-1], ystr[0..0], ystr[1..-1]
if x == y
x + lcs(xs, ys)
else
[lcs(xstr, ys), lcs(xs, ystr)].max_by {|x| x.size}
end
end
but my function is taking an extraordinarily long time. Note my benchmark below
2.4.0 :011 > timing = Benchmark.measure { StringHelper.lcs("navesxkolsky|1227000", "navsxkolsky|1227000") }
=> #<Benchmark::Tms:0x007fa1753830d8 #label="", #real=21.341279999993276, #cstime=0.0, #cutime=0.0, #stime=0.030000000000000027, #utime=21.28, #total=21.310000000000002>
Is there something I'm missing here that can get my comparison time down to like one second instead of 21?
Try this. The main idea is that if the method is to return false, it will do so as soon as that is known, even if rudundant code is required. (The method below still works if the line return false if (sz1-sz2).abs > 1 is removed.)
def equal_but_one?(str1, str2)
sz1 = str1.size
sz2 = str2.size
return false if (sz1-sz2).abs > 1
i = [sz1, sz2].max.times.find { |i| str1[i] != str2[i] }
return false if i.nil?
case sz1 <=> sz2
when 0
str1[i+1..-1] == str2[i+1..-1]
when -1
str2[i+1..-1] == str1[i..-1]
when 1
str1[i+1..-1] == str2[i..-1]
end
end
equal_but_one?('cat', 'cut') #=> true
equal_but_one?('bates', 'bats') #=> true
equal_but_one?('buss', 'bus') #=> true
equal_but_one?('cat', 'cat') #=> false
equal_but_one?('pig', 'pigs') #=> true
equal_but_one?('pig', 'pegs') #=> false
equal_but_one?('', '') #=> false
equal_but_one?('', 'a') #=> true
require 'benchmark'
Benchmark.measure { equal_but_one?("navesxkolsky|1227000", "navsxkolsky|1227000") }.real
#=> 1.6000005416572094e-05

Why doesn't the ternary syntax work in this situation?

This is valid:
def prime? n
(2...n).each {|num| return false if n % num == 0 }
true
end
This is NOT valid
def prime? n
(2...n).each {|num| n % num == 0 ? return false : true }
end
Aren't these both saying the same thing? Why does the second example cause a syntax error?
Now why does this next example work in the ternary syntax?
def primes max
primes_arr = []
(2...max).map { |num| prime?(num) ? primes_arr << num : next }
primes_arr
end
That code cause a syntax error because the ruby interpreter don't know, where the arguments for return keyword has end up, the correct example is:
def prime? n
(2...n).each {|num| n % num == 0 ? ( return false ) : true }
end
Here is the next isn't really required just use boolean logic:
def primes max
primes_arr = []
(2...max).map { |num| prime?(num) && primes_arr << num }
primes_arr
end
If we do some optimization, we can do:
def prime? n
(2...n).all? {|num| n % num != 0 }
end
def primes max
(2...max).select {|num| prime?(num) }
end
Next level of optimization shell be this:
def primes max
(2...max).select {|num| (2...num).all? {|num1| num % num1 != 0 } }
end
primes 7
# => [2, 3, 5]
Adding parenthesis to explicitly state the way Ruby is interpreting what you have:
(2...n).each { |num| (n % num == 0 ? return false) : true }
We can verify this in that we get the same error message with and without the parenthesis:
SyntaxError: (eval):2: syntax error, unexpected keyword_false, expecting ':'
You can solve this by giving explicit parenthesis to force Ruby to interpret it how you want:
(2...n).each { |num| n % num == 0 ? (return false) : true }
Or you can only return false when the case is met (as you have in your question). Or, better yet, use any? instead:
(2...n).any? { |num| n % num != 0 }
Here's a proper usage of ternary operator (no operator at all :) )
def prime? n
!(2...n).any? {|num| n % num == 0 }
# or
# (2...n).all? {|num| n % num != 0 }
end
(1..10).each do |x|
puts "prime?(#{x}) \# => #{prime?(x)}"
end
# >> prime?(1) # => true
# >> prime?(2) # => true
# >> prime?(3) # => true
# >> prime?(4) # => false
# >> prime?(5) # => true
# >> prime?(6) # => false
# >> prime?(7) # => true
# >> prime?(8) # => false
# >> prime?(9) # => false
# >> prime?(10) # => false

If expression.nil? then expression else other expression

I find myself often seeing a pattern when I want to evaluate some expression, and if true give the result of the expression, or if false perform some other similar expression. For example
if hours.detect { |h| h.position > i && h.open == true }.nil?
hours.detect { |h| h.position >= 0 && h.open == true }
else
hours.detect { |h| h.position > i && h.open == true }
end
This code seems very redundant. Can someone suggest a more elegant way of doing this?
Thanks!
Try the code:
hh = hours.select {|h| h.open == true }
hh.detect { |h| h.position > i } || hh.detect { |h| h.position >= 0 }
In most cases (when h.open returns a boolean value) it can be transformed into the following one:
hh = hours.select {|h| h.open }
hh.detect { |h| h.position > i } || hh.detect { |h| h.position >= 0 }
You can first create a method
def detect_hours(i)
hours.detect { |h| h.position > i && h.open }
end
then just use below
detect_hours(i) || detect_hours(0)
I would do as below :
hh_true = hours.select {|h| h.open == true }
prc = prc hh_true.detect { |h| h.position >= 0 }
hh_true.detect(prc) { |h| h.position > i }
One example to illustrate this :
ary = ['fooo','fooo','foo']
prc = proc {ary.find{|e| e.size == 3}}
ary.detect(prc){|e| e.size == 5}
# => "foo"
ary.detect(prc){|e| e.size == 4 }
# => "fooo"
hours.sort! { |h1,h2|
((-1 if h1.open == false) || (1 if h1.position > i) || (0 if h1.position >= 0)) <=>
((-1 if h2.open == false) || (1 if h2.position > i) || (0 if h2.position >= 0))
}
hours[0] if hours[0].open
I think this works, but I'm not 100% sure. Basically, map hours to a number, sort those numbers, and it'll be the first element.
This is better if you don't expect to have any h.position > i cases, since you'll have to check the entire array anyway.
Alternatively, although I'm not sure on the syntax, use the ifnone feature in detect:
hours.find(lambda{hours.find{|h| h.open && h.position > 0}}){|h| h.open && h.position > i}
The most straightforward solution is:
hours.detect { |h| h.position > i && h.open == true } || \
hours.detect { |h| h.position >= 0 && h.open == true }
But is it the most efficient? At first glance, one would think not, that it is better to first select those hours for which h.open == true. But recall that detect quits once it finds a true condition, which could be the first element of hours in the first block or the last element of hours in the second block. Relative efficiency will depend on the data. If h.position > i is usually true, this may well be faster than first doing a select, which requires a complete traversal of hours. If efficiency is important, one might test this, as well as the effect of reversing the two &&'ed conditions in each block.
hours.detect { |h| h.position > i && h.open == true } is repeated exactly twice. In many languages you can store it into some variable:
var1 = hours.detect { |h| h.position > i && h.open == true }
then in your if, you can substitute it:
if var1.nil?
hours.detect { |h| h.position >= 0 && h.open == true }
else
var1
end
You can get rid off nil? by using unless:
var1 = hours.detect { |h| h.position > i && h.open == true }
unless var1
hours.detect { |h| h.position >= 0 && h.open == true }
else
var1
end
In this if, hours.detect is exact the same. You can extract it into method/lambda/proc. Here is method version:
def hourse_detect hours, &lam # `&` change block of code into variable(`proc` / `lambda`) OR variable(`proc` / `lambda`) into block of code
hours.detect &lam #detect need block of code not `proc` / `lambda`
end
and your you can store blocks of code that exist between { and } (or do / end):
block1 = proc { |h| h.position > i && h.open == true }
block2 = proc { |h| h.position >= 0 && h.open == true }
Here is full code using above feautures:
def hourse_detect hours, &lam
hours.detect &lam
end
block1 = proc { |h| h.position > i && h.open == true }
block2 = proc { |h| h.position >= 0 && h.open == true }
var1 = hourse_detect hours, &block1
unless var1
hours_detect hours, &block2
else
var1
end
h.open == truecan be transformed into:
def opened? hour
hours.open == true
end

Why does && in Ruby sometimes shortcut evaluates and sometimes doesnt?

I want to test if an element in a hash exists and if it is >= 0, then put true or false into an array:
boolean_array << input['amount'] && input['amount'] >= 0
This raises no >= on NilClass error. However, if I just do this:
input['amount'] && input['amount'] >= 0 #=> false
No problem. Basically:
false && (puts 'what the heck?') #=> false
arr = []
arr << false && (puts 'what the heck?') #=> stdout: 'what the heck?'
arr #=> [false]
What gives?
<< has more precedence than &&. See Ruby Operator Precedence.
Currently it's being grouped as:
(boolean_array << input['amount']) && input['amount'] >= 0
Try:
boolean_array << (input['amount'] && input['amount'] >= 0)
However, if it ends up being false, the expression returns nil, so you want:
boolean_array << (!input['amount'].nil? && input['amount'] >= 0)
&& is always evaluated short circuit in Ruby.
The problem is << is before && in precedence, see Rubydoc:precedence
So the line
arr << false && (puts 'what the heck?')
is actually:
(arr << false) && (puts 'what the heck?')

Resources