How do I add a number to a hash? - ruby

In my code I have a hash, each one with a set value of 0, after running through the code, I would like it to display "1", but it only displays a 0. Can anyone help, and please explain my error and why it didn't work.
puts "Hello!, and welcome to the 'Coin Calculator V1.0', please enter a value."
coin_value = gets.to_i
coin_num = {"quarters" => 0,"dimes" => 0,"nickels" => 0,"pennies" => 0}
if coin_value>25
coin_value-25
coin_num["quarters"]+1 // **basically, how do I add an integer value to the old integer?
puts coin_num["quarters"]
end

coin_num["quarters"] = coin_num["quarters"] + 1
which can be shortened using the += operator (addition assignment):
coin_num["quarters"] += 1

Neither of your arithmetic expressions changes anything.
coin_value - 25
That evaluates to 25 less than coin_value; if you printed it out or assigned it somewhere, you would see that. But since you don't do anything with the value, it just gets thrown away and nothing happens. Certainly, coin_value doesn't change.
Similarly,
coin_num["quarters"] + 1
evaluates to one more than the current value of coin_num["quarters"], but doesn't change anything.
If you want to change the value of a variable - any variable, whether a simple scalar like coin_value or an element of a Hash or Array - you have to use an assignment statement. You need an =, and the variable you want to change has to be on the left hand side of that =:
coin_value = coin_value - 25
coin_num['quarters'] = coin_num['quarters'] + 1
Ruby does define shorthand operators for modifying a variable using a simple expression involving that same variable's previous value:
coin_value -= 25
coin_num['quarters'] += 1
But you're still using = - it's just part of a compound assignment operator now.

Related

Expressing "equals" in pseudocode

I was just wondering if there is a special way of saying when something equals something. For example in python, if you declare something equals 2, you say something = 2, whereas when you check if something equals something else, you would say:
if something == somethingelse:
So my question is in pseudocode for algorithms if I'm checking to see if a entered password equals a stored password in an IF THEN ELSE ENDIF loop, would I use one or two equal signs:
WHILE attempts < 3
Get EnteredPassword
**IF EnteredPassword = StoredPassword THEN**
Validated = TRUE
ELSE
attempts = attempts + 1
ENDIF
ENDWHILE
Usually, pseudocode is very broad and every author has their own way of expressing it. As
Aziz has noted, usually x <- 1 is used for an assignment and x := x + 1 for an update. Read ':=' as 'becomes' instead of 'equals', however, they are interchangeably used. As for your question, both = and == are accepted answers, as long as it is clear to your reader what your intention is.
To express equals you use the equal mark symbol once, unlike in python where you use the symbol twice to compare two values (eg if variable == 'one'). An example syntax is:
variable = 'one'
WHILE variable = 'one' DO
SEND "hi" TO DISPLAY

What the does the line if a = b mean in ruby code? [duplicate]

This question already has answers here:
Why does single `=` work in `if` statement?
(5 answers)
Closed 6 years ago.
I am trying to understand a particular line in the following piece of code:
def roman_to_integer(roman_string)
prev = nil
roman_string.to_s.upcase.split(//).reverse.inject(0) do
|running_sum, digit|
if digit_value = DIGITS[digit]
if prev && prev > digit_value
running_sum -= digit_value
else
running_sum += digit_value
end
prev = digit_value
end
running_sum
end
end
Can someone please help me understand when the line if digit_value = DIGITS[digit] means? are we assigning the value corresponding to the key 'DIGIT' from the hash to the digit_value here?
are we assigning the value
Yes, we are. And we also check the truthiness of the operation. Assignment operator returns the value that was assigned. Now, if it was a digit, it will be a truthy result and control will enter the if.
If DIGITS[digit] returns nil or false, it will be assigned to digit_value and also it will also become result of the assignment operation. Those values are falsey, so we would enter the else, if we had one there. But we don't, so we just skip the if.
are we assigning the value corresponding to the key 'DIGIT' from the hash to the digit_value here?
Yes that is exactly what is happening. The temporary variable is slightly easier to read than the extraction from the hash. In similar circumstances, obtaining the value might be more expensive (think of a database read for example instead of a Hash lookup), so it is not a bad practice to get into.
The assignment operator also returns the value assigned for the if statement to work.
Alternative equivalent syntax is a bit more verbose:
digit_value = DIGITS[digit]
if digit_value
# .... etc
so this is also a common style choice when assigning a value to a variable and wanting to check its truthiness immediately.
if digit_value = DIGITS[digit] will return true if DIGITS[digit] has value other than nil or false. This is because in Ruby nil and false are the only values that are considered falsy.
Ruby will first assign the value to variable and than evaluate if the value is falsy.

Why is Ruby printing out the variable and not the string?

With the following statement
print #b>#d?("S";#b+=1): #b<#d?("N";#b-=1):""
I want S to be output to the screen and then the value of b incremented if the val of b is higher than d. Otherwise check if b is lower than d and decrement b.
However, it seems that the value of b + 1 is printed instead. What is going on here?
In ruby methods, always the last line is returned by default. Change your code to
print #b>#d?(#b+=1; "S"): #b<#d?(#b-=1; "N"):""
In order to do what you want as an output.
The value of b+1 is the last thing returned here: ("S";#b+=1), thus, it is what gets evaluated by print. Let us try a simpler example:
x = 0
# => 0
puts (true ? ("X is incremented #{x+=1}"; "Only this is printed though") : "Never here")
# Only this is printed though
# => nil
x
# => 1
Although the first statement is executed, which increments x, only the last statement is passed as an argument to puts.

Why isn't `method=` treated the same as any other method?

Consider the following code snippet:
class Example
def my_attr=(value)
#_my_attr = value
#_my_attr * 3
end
end
I expect the expression Example.new.my_attr = 5 to return 15, but that turns out to be wrong. The original return value is always returned, even when I call the = method explicitly:
Example.new.my_attr = 5 # => 5
Example.new.my_attr=(5) # => 5
How and why does Ruby do this? Does Ruby treat methods that end in = specially, or is it some other mechanism? I guess this precludes chaining on return values of = methods, right? Is there a way to make Ruby behave differently, or is this just how it is?
Update: Credit to #jeffgran for this:
Example.new.send(:my_attr=, 5) # => 15
This is a workaround, but on another level even more perplexing, since that would mean send is clearly not always equivalent in behavior to calling a method directly.
This is how assignment works; the return value is ignored, and the result of an assignment expression is always the right-hand value. This is a fundamental feature of Ruby's grammar. left-hand side = right-hand side will always evaluate to right-hand side, regardless of whether left hand side is a variable (x), a method (object.x), a constant (X) or any expression.
Source: Programming Languages | Ruby
IPA Ruby Standardization WG Draft, 11.4.2.2.5, Single method assignments
Consider chaining of assignments, x = y = 3.
For this to work correctly, the result of y = 3 must be 3, regardless of the actual value returned by the y= method. x = y = 3 is meant to read as y = 3; x = 3, not as y = 3; x = y which is what would be implied if the return value from y= was treated as the result of y = 3.
Or consider all the other places assignment can be used. Sometimes, instead of this...
obj.x = getExpensiveThing()
if obj.x
...
... we write this ...
if obj.x = getExpensiveThing()
This couldn't work if the result of obj.x = ... could be any arbitrary thing, but we know it will work because the result of obj.x = y is always y.
Update
A comment on the question states:
Interesting, I wasn't aware of this scenario. It seems that method= returns whatever input is given...
No, it's an important distinction to make. This has nothing to do with the return value of method assignment, and it definitely does not "return whatever input is given", it returns whatever you tell it to return.
The whole point is that the return value is ignored by the grammar of the language; assignment doesn't evaluate to the return value of the attr= method, but the return value still exists as evidenced by the question itself: Example.new.send(:my_attr=, 5) # => 15. This works because it is not assignment. You're side-stepping that part of the Ruby language.
Update again
To be clear: x and y in my examples shouldn't be interpreted as literal Ruby variables, they are place holders for any valid left-hand side of an assignment. x or y could be any expression: a, obj.a, CONSTANT_A, Something::a, #instance_a, it's all the same. The value of assignment is always the right-hand side.

Rails iteration math operator causes a wrong number of arguments

This iteration prints the highest index value.
It works and prints 8 eight times.
- #videos.each_with_index do |video, index|
= index.size
When I add a math operator it doesn't work and gives me this error: wrong number of arguments (1 for 0)
- #videos.each_with_index do |video, index|
= index.size - 1
index in your example is a Fixnum, the index of the element in the enumeration. Fixnum#size returns the number of bytes in the machine representation of a Fixnum. Probably not what you were looking for. It accepts zero arguments which explains the exception you got.
The fact that index.size returns 8 is because you're running on a 64bit architecture and has nothing to do with the size of #videos.
It seems like:
index.size - 1
is being interpreted as:
index.size(-1)
Try adding in parenthesis to force it to be interpreted in the correct way:
(index.size) - 1
or:
index.size() - 1

Resources