How to write multiline arithmetic properly in Ruby? Previously, i have tried something like y, then i realized there is something wrong with that code. I need to write multiline arithmetic due to my very long equation.
a = 5
b = 5
x = (a + b) / 2
puts x # 5, as expected
y = (
a
+ b
) /
2
puts y # 2, what happened?
The Ruby parser will assume a statement has ended if it looks like it has ended at an end of the line.
What you can to do prevent that is to leave the arithmetic operator just before a new line, like this:
a = 1
b = 2
c = a +
b
And you'll get the result you expect.
(
expr1
expr2
)
is actually, in Ruby, the same as
(expr1; expr2)
which just executes the first expression (for side effects) and returns the second one (also after evaluating it)
Try thinking about the "expectations" of the interpreter, and remember that in ruby EVERYTHING is an expression (which means that everything evaluates to some value, even constructs that in other languages are considered "special", like if-then-elses, loops, etcettera).
So:
y = ( #1
a #2
+ b #3
) / #4
2 #5
At line 1 we start the declaration of a variable, and the line ends with an open (pending) parenthesis. The interpreter expects the rest of the definition, so it proceeds to the next line looking for a VALUE to assign to the var y.
At line 2, the interpreter finds the variable a, but no enclosing parenthesis. It evaluates a, which has value 5, and since the line 2 is a perfectly-valid expression, the interpreter understands that this expression is finished (since in Ruby a newline OFTEN means end-of-expression indicator).
So up to now it has produced a value 5, but the only expectation it still has is that it must match the enclosing parenthesis.
If after that the interpreter had found the enclosing parenthesis, it would have assigned the value of a (i.e. 5) to the parenthesis expression (because everything must have a value, and the last value produced will be used).
When the interpreter reaches line 3, it finds another perfectly-valid ruby expression, + b. Since + 5 (5 being the value of variable b) is a VALID integer declaration in ruby, the interpreter sees it as standalone, not at all related to the previous 5 evaluated for the variable a (remember, it had no other expectation, except the one for the parenthesis).
In short, it throws away the value obtained for a, and uses only the value obtained with + b. In the next line it finds the enclosing parenthesis, and so the parenthesis-expression gets assigned the last produced value, which is a 5 produced by the expression + b.
Since on line 4 the interpreter finds a /, it (correctly) understands it as the division method of an integer, since it has produced an integer up to now (the int 5)! This creates the expectation for possible arguments of the method, which it finds on line 5. The resulting evaluated expression is y = 5 / 2, which equals 2 in integer division. So, basicaly, here is what the interpreter did:
y = ( # Ok, i'm waiting for the rest of the parenthesis expression
a # cool, a has value 5, if the parenthesis ends here, this is the value of the expr.
+ b # Oh, but now I found + b, which has value + 5, which evaluates to 5. So now this is the last value I have evaluated.
) / # Ok, the parenthesis have been closed, and the last value I had was a 5. Uow, wait, there is a slash / there! I should now wait for another argument for the / method of the 5 I have!
2 # Found, let's make y = 5 / 2 = 2!
The problem here is that on line #2, you should have left an expectation for the interpreter (exactly as you left on line 4 with the / method), which you did not!
The answer of #Maurício Linhares suggests exactly this:
y = (
a +
b
) /
2
By moving the + method to the end of the line 2, you tell the interpreter that your expression is still not complete! So it keeps the expectation and proceeds to line #3 to find the right operand of the expression (or, more precisely in Ruby, an argument for the + method :D).
The same works with string concatenation:
# WRONG, SINCE + "somestring" is not a valid stand-alone expression in ruby
str = "I like to"
+ " move it!"
# NoMethodError: undefined method `+#' for " move it!":String
# CORRECT, by leaving the + sign as last statement of the first line, you
# keep the 'expectation' of the interpreter for the next
# argument of the + method of the string object "I like to"
str = "I like to" +
" move it!"
# => "I like to move it!"
The difference is that in your code there were no error thrown, since + b is actually a valid expression.
I hope my answer was useful on giving you some intuition on WHY it was not working as expected, sorry if I'm not concise :)
Related
The distilled script is the following:
z1 = (12 -
2) / (5)
z2 = (12
- 2) / (5)
puts(z1.to_s + " " + z2.to_s)
Which gives:
$ ruby rubytest.rb
2 -1
Now, I'm aware that the z1 case is the right way to do it, because a hanging operator on the end of the line is interpreted as an automatic continuation of the line.
However, I would expect the interpreter to fail-fast on the z2 case, and tell me that the statement is incomplete, or that its second line is nonsensical. But it handles it "just fine" and gives the "-1" answer. Is it trying to appear confident by not admitting it's confused and hoping the bullshit answer will go unnoticed?
Could someone explain what is actually happening with the evaluation of z2, why is it "-1", why is there no syntax error, and is there an example where this behaviour is useful (or should we file a request to remove it)?
It's a feature, but you might think it's a bug at first. It's for the same reason you are able to do this (which is handy many cases):
(call_function_1; call_function_2) if some_condition
A line feed is interpreted the same as ;. You will notice this evaluates fine for example, and only the last expression is returned, but all expression ARE evaluated none the less:
(1
2
3
4
5)
=> 5
It's the same as
(1; 2; 3; 4; 5)
=> 5
To see that all expressions are evaluated you can try this for example:
(puts "A"
puts "B"
puts "C"
123)
A
B
C
=> 123
So your example becomes:
(12; -2) / 5
Which is the same as:
-2 / 5
Which is -1.
To make Ruby interpret 12 as an unfinished statement and not a separate statement you can tell Ruby this by adding a line continuation hint \:
(12 \
- 2) / 5
=> 2
I came across a bit of an oddity (am using Ruby 1.9.1). Case scenario being:
class D
...
def self.d6
1+rand(6)
end
...
end
v = D::d6+2 # fine and dandy
v = D::d6 +2 # in `d6': wrong number of arguments (1 for 0) (ArgumentError)
v = D::d6 + 2 # fine and dandy
Why the "+2" in second case is treated as being "positive 2" and not an "addition of 2"?
The + same as the - in ruby are overloaded in order to make the syntax look nice.
When there is no space the Ruby parser recognizes the + as the method which is called on the result of d6 which is an Integer.
Same goes for the version with space before and after the +.
However: In the operator precedence in Ruby + as a unary operator is defined before + as a binary operator (as is often the case in other languages as well).
Therefore if there is a space before the + but not after it, the Ruby Parser will recognize it as d6(+2) which fits the error message.
I am currently working on a Ruby Problem quiz but I'm not sure if my solution is right. After running the check, it shows that the compilation was successful but i'm just worried it is not the right answer.
The problem:
A string S consisting only of characters '(' and ')' is called properly nested if:
S is empty,
S has the form "(U)" where
U is a properly nested string,
S has
the form "VW" where V and W are
properly nested strings.
For example, "(()(())())" is properly nested and "())" isn't.
Write a function
def nesting(s)
that given a string S returns 1 if S
is properly nested and 0 otherwise.
Assume that the length of S does not
exceed 1,000,000. Assume that S
consists only of characters '(' and
')'.
For example, given S = "(()(())())"
the function should return 1 and given
S = "())" the function should return
0, as explained above.
Solution:
def nesting ( s )
# write your code here
if s == '(()(())())' && s.length <= 1000000
return 1
elsif s == ' ' && s.length <= 1000000
return 1
elsif
s == '())'
return 0
end
end
Here are descriptions of two algorithms that should accomplish the goal. I'll leave it as an exercise to the reader to turn them into code (unless you explicitly ask for a code solution):
Start with a variable set to 0 and loop through each character in the string: when you see a '(', add one to the variable; when you see a ')', subtract one from the variable. If the variable ever goes negative, you have seen too many ')' and can return 0 immediately. If you finish looping through the characters and the variable is not exactly 0, then you had too many '(' and should return 0.
Remove every occurrence of '()' in the string (replace with ''). Keep doing this until you find that nothing has been replaced (check the return value of gsub!). If the string is empty, the parentheses were matched. If the string is not empty, it was mismatched.
You're not supposed to just enumerate the given examples. You're supposed to solve the problem generally. You're also not supposed to check that the length is below 1000000, you're allowed to assume that.
The most straight forward solution to this problem is to iterate through the string and keep track of how many parentheses are open right now. If you ever see a closing parenthesis when no parentheses are currently open, the string is not well-balanced. If any parentheses are still open when you reach the end, the string is not well-balanced. Otherwise it is.
Alternatively you could also turn the specification directly into a regex pattern using the recursive regex feature of ruby 1.9 if you were so inclined.
My algorithm would use stacks for this purpose. Stacks are meant for solving such problems
Algorithm
Define a hash which holds the list of balanced brackets for
instance {"(" => ")", "{" => "}", and so on...}
Declare a stack (in our case, array) i.e. brackets = []
Loop through the string using each_char and compare each character with keys of the hash and push it to the brackets
Within the same loop compare it with the values of the hash and pop the character from brackets
In the end, if the brackets stack is empty, the brackets are balanced.
def brackets_balanced?(string)
return false if string.length < 2
brackets_hash = {"(" => ")", "{" => "}", "[" => "]"}
brackets = []
string.each_char do |x|
brackets.push(x) if brackets_hash.keys.include?(x)
brackets.pop if brackets_hash.values.include?(x)
end
return brackets.empty?
end
You can solve this problem theoretically. By using a grammar like this:
S ← LSR | LR
L ← (
R ← )
The grammar should be easily solvable by recursive algorithm.
That would be the most elegant solution. Otherwise as already mentioned here count the open parentheses.
Here's a neat way to do it using inject:
class String
def valid_parentheses?
valid = true
self.gsub(/[^\(\)]/, '').split('').inject(0) do |counter, parenthesis|
counter += (parenthesis == '(' ? 1 : -1)
valid = false if counter < 0
counter
end.zero? && valid
end
end
> "(a+b)".valid_parentheses? # => true
> "(a+b)(".valid_parentheses? # => false
> "(a+b))".valid_parentheses? # => false
> "(a+b))(".valid_parentheses? # => false
You're right to be worried; I think you've got the very wrong end of the stick, and you're solving the problem too literally (the info that the string doesn't exceed 1,000,000 characters is just to stop people worrying about how slow their code would run if the length was 100times that, and the examples are just that - examples - not the definitive list of strings you can expect to receive)
I'm not going to do your homework for you (by writing the code), but will give you a pointer to a solution that occurs to me:
The string is correctly nested if every left bracket has a right-bracket to the right of it, or a correctly nested set of brackets between them. So how about a recursive function, or a loop, that removes the string matches "()". When you run out of matches, what are you left with? Nothing? That was a properly nested string then. Something else (like ')' or ')(', etc) would mean it was not correctly nested in the first place.
Define method:
def check_nesting str
pattern = /\(\)/
while str =~ pattern do
str = str.gsub pattern, ''
end
str.length == 0
end
And test it:
>ruby nest.rb (()(())())
true
>ruby nest.rb (()
false
>ruby nest.rb ((((()))))
true
>ruby nest.rb (()
false
>ruby nest.rb (()(((())))())
true
>ruby nest.rb (()(((())))()
false
Your solution only returns the correct answer for the strings "(()(())())" and "())". You surely need a solution that works for any string!
As a start, how about counting the number of occurrences of ( and ), and seeing if they are equal?
Why does this throw a syntax error? I would expect it to be the other way around...
>> foo = 5
>> foo = foo++ + ++foo
=> 10 // also I would expect 12...
>> foo = (foo++) + (++foo)
SyntaxError: <main>:74: syntax error, unexpected ')'
foo = (foo++) + (++foo)
^
<main>:75: syntax error, unexpected keyword_end, expecting ')'
Tried it with tryruby.org which uses Ruby 1.9.2.
In C# (.NET 3.5) this works fine and it yields another result:
var num = 5;
var foo = num;
foo = (foo++) + (++foo);
System.Diagnostics.Debug.WriteLine(foo); // 12
I guess this is a question of operator priority? Can anybody explain?
For completeness...
C returns 10
Java returns 12
There's no ++ operator in Ruby. Ruby is taking your foo++ + ++foo and taking the first of those plus signs as a binary addition operator, and the rest as unary positive operators on the second foo.
So you are asking Ruby to add 5 and (plus plus plus plus) 5, which is 5, hence the result of 10.
When you add the parentheses, Ruby is looking for a second operand (for the binary addition) before the first closing parenthesis, and complaining because it doesn't find one.
Where did you get the idea that Ruby supported a C-style ++ operator to begin with? Throw that book away.
Ruby does not support this syntax. Use i+=1 instead.
As #Dylan mentioned, Ruby is reading your code as foo + (+(+(+(+foo)))). Basically it's reading all the + signs (after the first one) as marking the integer positive.
Ruby does not have a ++ operator. In your example it just adds the second foo, "consuming" one plus, and treats the other ones as unary + operators.
-> irb
>> (Date.today +3).to_s
=> "2009-10-22"
>> (Date.today + 3).to_s
=> "2009-10-25"
between "+3" and "+ 3", there is a difference?
"+3" with no space means positive 3, which gets passed to the today method as an argument, while "+ 3" means plus three, so the return value of the today method gets added to 3.
In case you're curious, the optional parameter to the today method "specifies the Day of Calendar Reform", for conversions to other date formats.
I realize this must have been a frustrating bug to discover. When using a language where method invocation has optional parentheses, whitespace is a delicate matter. Consider the following:
square(2+2)*2 # square(4)*2 = 16*2 = 32
square (2+2)*2 # square(4*2) = square(8) = 64
Your case is trickier because the +3 with no space is actually a unary operator. ! ~ and + unary operators have the highest precedence.
Also interesting the - unary operator has a lower precedence than the exponentiation operator. Therefor
-4**2 # -(4**2) = -16
It seems to me that the + binds to the 3 in the first case. That is the interpreter sees Date.today(+3). If there's a space after the plus the interpreter instead sees (Date.today) + (3).
Using + to denote positive numbers isn't very common since numbers are positive to begin with, but consider the case of negative numbers: it's easier to see that Date.today -3 means something else than Date.today - 3.