I'd like to write a conditional lambda in Ruby. The Python equivalent of what I'd like to write is:
even = (lambda x: x if x % 2 == 0 else 0)
My attempt to write this in Ruby looks like:
even = -> (x) {x if x % 2 == 0 else 0}
Unfortunately, that does not work. Is there any way to fix this?
You have several options here to express this. The long-form is this:
if (x % 2 == 0)
x
else
0
end
Note that a trailing if or unless cannot have a secondary condition like else. You need to use the full form.
If you want a short version, you use the ternary operator:
(x % 2 == 0) ? x : 0
What you could also do is this:
(x % 2 == 0) and x or 0
As others have observed there's a method called even? which does the modulo for you, so that can collapse this further:
x.even? ? x : 0
Ruby's ternary operator has this syntax
x % 2 == 0 ? x : 0
You don't even need a conditional.
p = ->(x) { x*(1-x%2) }
p.call(4) #=> 4
p.call(5) #=> 0
Note procs can be called in multiple ways:
p[4] #=> 4
p.(4) #=> 4
p.yield(4) #=> 4
p === 4 #=> 4
p(4) #=> 4
The last of these may be archaic.
Wrong syntax. You can write it like this:
even = -> (x) {if x % 2 == 0; x; else; 0; end}
However, for such one-liners, it is more common to use the ternary ?: operator, as other have suggested in this thread.
Your syntax is wrong:
The then-block comes after the condition, not before it.
The then-block is separated from the condition by the then keyword, a semicolon, or a newline.
The conditional expression is terminated with an end keyword.
So, any of the following is valid:
# idiomatic:
if x % 2 == 0 then x else 0 end
# idiomatic:
if x % 2 == 0
x
else
0
end
# non-idiomatic:
if x % 2 == 0; x else 0 end
# non-idiomatic:
if x % 2 == 0 then
x
else
0
end
# non-idiomatic:
if x % 2 == 0
x else 0 end
# … and many other non-idiomatic variations
Ruby also has a conditional operator:
x % 2 ? x : 0
But I personally find it ugly and unreadable. It also has different precedence than the conditional expression, which may be surprising to some. (Witness the myriad of variations of the same question about the conditional operator here on StackOverflow.) And it is completely unnecessary: in C, where if is a conditional statement, the conditional operator is required because it is an expression. In Ruby, everything is an expression anyway, there are no statements, so of course if is an expression, too.
Related
This might be a silly question, but in some function I have two int s, and need to compare them to find if exactly one of them is ==0... Both of the ways I came up with require 5 logical operations, and I can't think of anything shorter... Is there a shorter way?
What I came up with is:
int x, y;
if (((x==0) || (y==0)) && (x != y)){} // most obvious option, or:
if (((x^y) == x) ^ ((x^y) == y)){} // looks better, but still 5 ops
The expression ((x^y) == x) ^ ((x^y) == y) can be simplified in a straightforward way.
(x^y) == x if and only if y == 0, and likewise (x^y) == y if and only if y == 0. So the following uses three operations to compute the condition:
if((x == 0) ^ (y == 0)) {
// ...
}
This makes sense because using XOR as a logical operator, the result is true if and only if one but not both of the operands is true. So this directly tests whether one but not both of x == 0 and y == 0 are true.
I have a quick question :
In ruby, If I write
def test
foo && a == b && c == "bar"
end
if foo is null or false, will it keep evaluating the rest of the expression ?
Does it change anything if I do this instead
def test
a == b && c == "bar" if foo
end
thanks a lot
Theory
&& is a lazy operator, just like ||.
It means that in a && b, if a is false or nil, Ruby won't bother to check b because a && b will be false/nil anyway.
This behaviour is actually desired, because it saves time and could avoid NoMethodErrors.
if a && method_which_requires_a_non_nil_parameter(a)
# ...
end
method_which_requires_a_non_nil_parameter wouldn't be called at all if a is nil.
or :
x = x || long_method_to_calculate_x
is often used for caching, more often written as :
#x ||= long_method_to_calculate_x
Answer
def test
foo && a == b && c == "bar"
end
The rest of the expression won't be evaluated if foo is nil or false :
a, b, c could even be undefined without raising a NameError.
def test
a == b & c == "bar" if foo
end
If foo is truthy, the results will be exactly the same.
If foo is nil or false, the 2 equalities won't be evaluated, just like with the first example. But :
If foo is nil, both test will return nil.
If foo is false, first example will return false, second example will return nil.
"If foo is null or false, will it keep evaluating the rest of the expression?"
No, it will not
This table should help you in such questions:
The following table is ordered according to descending precedence (highest precedence at the top)
N A M Operator(s) Description
- - - ----------- -----------
1 R Y ! ~ + boolean NOT, bitwise complement, unary plus
(unary plus may be redefined from Ruby 1.9 with +#)
2 R Y ** exponentiation
1 R Y - unary minus (redefine with -#)
2 L Y * / % multiplication, division, modulo (remainder)
2 L Y + - addition (or concatenation), subtraction
2 L Y << >> bitwise shift-left (or append), bitwise shift-right
2 L Y & bitwise AND
2 L Y | ^ bitwise OR, bitwise XOR (exclusive OR)
2 L Y < <= >= > ordering
2 N Y == === != =~ !~ <=> equality, pattern matching, comparison
(!= and !~ may not be redefined prior to Ruby 1.9)
2 L N && boolean AND
2 L N || boolean OR
2 N N .. ... range creation (inclusive and exclusive)
and boolean flip-flops
3 R N ? : ternary if-then-else (conditional)
2 L N rescue exception-handling modifier
2 R N = assignment
2 R N **= *= /= %= += -= assignment
2 R N <<= >>= assignment
2 R N &&= &= ||= |= ^= assignment
1 N N defined? test variable definition and type
1 R N not boolean NOT (low precedence)
2 L N and or boolean AND, boolean OR (low precedence)
2 N N if unless while until conditional and loop modifiers
I wonder why the first approach to factorial does not work (infinite loop) in ruby while the second does.
def fac (x)
if x == 0
return 1
else
return (fac (x-1) * x)
end
end
def fact( num )
return 1 if num == 0
fact(num - 1) * num
end
The difference is the space after the method name, not the way you structured your if-else.
fac (x-1) * x is parsed as fac((x-1) * x). Basically if a method name is followed by a space (or any token that is not an opening parenthesis), ruby assumes you're calling the method without parentheses. So it interprets the parentheses around x-1 as grouping, not a part of the method call syntax.
I understand that x == y in Ruby interpreted as a.==(y). I tried to check if I can achieve the same with custom method, foo, like this:
class Object
def foo(n)
self == n
end
end
class A
attr_accessor :x
end
a = A.new
a.x = 4
puts a.x.==(4) # => true
puts a.x.foo(4) # => true
puts a.x == 4 # => true
puts a.x foo 4 # => in `x': wrong number of arguments (1 for 0) (ArgumentError)
Unfortunately, this doesn't work. What am I missing ? Is == a special method in Ruby ?
No, == is not a special method in Ruby. It's a method like any other. What you are seeing is simply a parsing issue:
a.x foo 4
is the same as
a.x(foo(4))
IOW, you are passing foo(4) as an argument to x, but x doesn't take any arguments.
There is, however, special operator syntax, which allows you to write
a == b
instead of
a.== b
for a limited list of operators:
==
!=
<
>
<=
>=
<=>
===
&
|
*
/
+
-
%
**
>>
<<
!==
=~
!~
Also, there is special syntax that allows you to write
!a
and
~a
instead of
a.!
and
a.~
As well as
+a
and
-a
instead of
a.+#
and
a.-#
Then, there is
a[b]
and
a[b] = c
instead of
a.[] b
and
a.[]= b, c
and last but not least
a.(b)
instead of
a.call b
Methods that are operators are treated specially in Ruby, at least syntax-wise. The language is not as flexible as, say, in Haskell where you can turn any function into an infix operator by enclosing its name in backticks: the list on infix operators are pre-determined.
One of the problems that would arise from custom infixes is the handling of operator precedence and associativity: for eaxmple, how would the parser handle a statement like:
a foo b == c # should this be (a foo b) == c or a foo (b == c)
Consider the following code:
x = 4
y = 5
z = (y + x)
puts z
As you'd expect, the output is 9. If you introduce a newline:
x = 4
y = 5
z = y
+ x
puts z
Then it outputs 5. This makes sense, because it's interpreted as two separate statements (z = y and +x).
However, I don't understand how it works when you have a newline within parentheses:
x = 4
y = 5
z = (y
+ x)
puts z
The output is 4. Why?
(Disclaimer: I'm not a Ruby programmer at all. This is just a wild guess.)
With parens, you get z being assigned the value of
y
+x
Which evaluates to the value of the last statement executed.
End the line with \ in order to continue the expression on the next line. This gives the proper output:
x = 4
y = 5
z = (y \
+ x)
puts z
outputs 9
I don't know why the result is unexpected without escaping the newline. I just learned never to do that.
Well you won't need the escaping character \ if your lines finishes with the operator
a = 4
b = 5
z = a +
b
puts z
# => 9