Reputation: 125
This part of code calculates the value of each arithmetic series up to and including the number that the user put in:
print "enter a number: "
num = gets.to_i
(1..num).inject(0) do |res, e|
res += e
p res
end
I think that (1..num)
is the range, with num
being the user input. I know that inject
combines all elements of enum by applying a binary operation specified by a block or a symbol that names a method or operator.
I don't understand what each element in this line does:
(1..num).inject(0) do |res, e|
|res, e|
mean? It must be the block that defines what inject
does, but what does for instance res
and e
stand for? (e
is probably element?)(0)
stand for?do
do?(1..num)
and inject(0)
?p
at the end just stands for puts
or print
?Upvotes: 2
Views: 238
Reputation: 27793
Excited to see that you're learning Ruby, welcome!
At your level of expertise best learn from a book.
Some quick answers
1..num
is a range object.inject(0) do ... end
is a method call with TWO parameters, the value 0
and a code blockdo |a, b| ... end
is a code block with two parametersres
and e
are VERY bad variable names, maybe better use sum
and each
?p
is a global method that prints debug information, similar to puts
but not the sameHope that helps to unblock you.
Upvotes: 1
Reputation: 1047
inject
is a method that boils a collection (eg an array or range) down to a single value. It does this by executing the block once for each element in the collection. The block takes two arguments: the current value being worked on, and the single value that will eventually be returned. inject
itself takes one argument (aside from the block), which is its initial starting value.
Take this example.
x = [1, 2, 3, 4, 5].inject(0) do |result, current|
result + current
end
We have a list of numbers, [1, 2, 3, 4, 5]
. We're going to boil them down into one single number.
We start with 0
, because that's inject
's argument. That means that the first time the block runs, result
will be 0.
So the block runs for the first time. result
is 0, current
is 1, the first element. We say result + current
(which is 1
). It's the last expression inside the block, so it's what that block 'returns'.
At the end of the block, inject
says "Okay, do we have more elements in the collection?" Yeah. So the block runs again. This time, result
is whatever the last block returned, which was 1, and current
is the second element, 2
.
The block runs, and finishes with result + current
, or 1 + 2, which is 3. There are still elements left, so we run again. This time, result
is 3, and current
is 3. result + current
, 6. Still more values to go, on the next run result
is 6 and current
is 4. 6 + 4 = 10. Still more values to go, on the next run result
is 10 and current
is 5. 10 + 5 = 15.
Then the block finishes, and there are no more elements left. So inject
itself returns with the final value, 15. So in the end, x = 15
. We boiled down our list into one number by adding things up.
res
in your example stands for result, and e
for element. You can call them anything you want. You might call them sum
while adding, or product
if multiplying. But they don't have to be numbers. You could use inject
to boil an array of strings, a range of characters, an array of arrays, whatever collection you want. The block just tells it how.
Upvotes: 3
Reputation: 198314
inject
takes an optional start value, and a block taking an intermediate value and element and returning a new intermediate value.
So:
What does (0) stand for?
The start value parameter to inject
.
What does the command "do" do?
It is not a command; it marks the start of the block (terminated by end
). .inject(0) do ... end
is almost (except for some syntactic issues) the same as .inject(0) { ... }
. Usually, do ... end
is used for multi-line blocks and { ... }
for single-line blocks, but it is not a rule.
What does |res, e| mean?
Those are the block parameters (intermediate value and current element), here probably called after "result" and "element", respectively.
Let's see on a simplified example: (1..3).inject(0) do |res, e| res + e end
will set the intermediate result to 0
. Then it will pass this intermediate result and the first element of the enumerable being injected: res
is 0
and e
is 1
. The value of the block is the value of its last expression, which is 1
(result of 0 + 1
). This 1
now becomes the new intermediate value, and 2
becomes the next current element. The value of the block is 3
(result of 1 + 2
). In the next iteration, intermediate value is 3
, and the current element also 3
, resulting in 6
(3 + 3
). The range will stop yielding elements now that we reached its upper boundary, and inject
returns with the last intermediate result calculated, 6
.
Also, the last question am I right to assume that "p" at the end just stands for puts or print?
Almost. p
is its own beast. p x
is roughly synonymous with puts x.inspect; x
- i.e. it prints the value in a bit different format, and unlike puts
which always returns nil
, p
returns the value unchanged. Thus, p res
at the end of your block will not destroy the code by making it return nil
, but transparently return res
.
Upvotes: 5