Understanding, Recursion in Ruby - ruby

In recursion, a method calls itself. I'm not following it when there are return values. For example, in the "Learn to Program" book by Chris Pine, there is this example on factorials.
def factorial num
if num < 0
return 'You cant\'t take the factorial of a negative number!'
end
if num <= 1
1
else
num * factorial(num-1)
end
end
If I call the method factorial(3), it will go to the else portion of the code and will look like this:
3 * factorial(3-1)
and should return 6 since 3*2=6. factorial(3-1) calls the factorial method passing 2 within the recursion. num = 2, and thus 2 * factorial(2-1) and 2*1=2.
What happens to the 6 that we got from our first run through the code? Now that num = 1, it looks like this will now return 1 and go to the end of the code. But from my understanding, we still have 6 and 2 from the previous recursions. Am I correct in this assumption, since we called the factorial function when we multiplied by num? Can someone help me understand this better? Say we called factorial(10), how would this work out?

Now what happens to the 6 that we got from our first run through the
code?
There was no 6 from the first run; the 6 only appeared at the end.
This is what happens:
factorial(3) → 3 * factorial(2)
factorial(3) → 3 * 2 * factorial(1)
factorial(3) → 3 * 2 * 1
There is no “memory” of previous calls in your function, each time factorial() is called, it's like a brand new function; is it clearer when written as multiple functions?
def factorialof3
3 * factorialof2
end
def factorialof2
2 * factorialof1
end
def factorialof1
1
end

Patrice answer splitting it up into separate functions is good, and if you have any background in computer science, it will also help to think of what data structures are probably at work here, mainly the Stack
So when you call factorial(3) it will go to that else block and 'stack' on another call to factorial(2)
and then stack another one with a call to factorial(1).
at that point, since num = 1, (recursion must always have a base case) factorial(1) will return 1.
Then because of the stack, the last one in is the first one out, so the factorial(1) will return 1, and that will 'fall' back down to the factorial(2) call, and because it was called in that else block, the call to factorial(2-1) will now be replaced by 1, and you will get 2*1, and I think by now you get the picture
It is also important to note, this example is trying to teach you recursion in general, and this example is not really idiomatic ruby. The solution alfasin posted as a comment is more like it.

First, you should replace your return 'blabla' with a raise 'blabla' because your function returns a numeric, not a string.
Then see it like this
factorial(3)
3 * factorial(2)
2 * factorial(1)
1 # no more recursion, let's go up replacing
# the function calls by the returned value
end
end
end
# ↓
factorial(3)
3 * factorial(2)
2 * 1 # let's go up again !
end
end
# ↓
factorial(3)
3 * 2 # finally
end
# ↓
6

Related

Is there a nicer way to call the current method recursively, without using its name?

For example:
def recurse(value)
if value < 5
self.send(__method__, value + 1)
else
value
end
end
This works, but it's a bit ugly.
Basically I'm looking for a prettier way to call the currently executing method, without referring to it explicitly by name.
If there is a less-cryptic syntax for this, I would probably use it (to avoid the name duplication, reduce effort required for renaming a function, etc). If there isn't a nicer syntax for this, I'll just hard-code the name like normal.
It's a comment rather, as #sagarpandya82 mentioned, you can omit some redundant parts and use both variants. I would refactor it a bit:
def recurse(value)
return value unless value < 5 # return value if value >= 5
send(__method__, value + 1) # or just recurse(value + 1)
end
Non-recursion version with a block:
def non_recurse(value)
if value >= 5
yield value
else
(value..5).each do |i|
yield i
end
end
end
non_recurse(3) {|i| puts i}
#=> 3, 4, 5
non_recurse(6) {|i| puts i}
#=> 6
If you really want to use __method__, your method is correct and reasonably readable. To comply with usual Ruby guidelines, you could just remove returns and use 2 spaces as indent (as mentioned by #sagarpandya82 in the comments):
def recurse(value)
if value < 5
self.send(__method__, value + 1)
else
value
end
end
I don't see any reason to use self.send(__method__) here, so you could write :
def recurse(value)
if value < 5
recurse(value + 1)
else
value
end
end
Actually, I'd say that you don't need recursion at all. All your method does is to keep adding 1 to the value until it reaches 5. If the value is bigger than 5, it returns the value :
For integers:
def no_recurse(value)
[value, 5].max
end
no_recurse(4)
# 5
no_recurse(-3)
# 5
no_recurse(7)
# 7
no_recurse(-2**1000)
# 5
no_recurse(4.5)
# 5 # <- That's wrong
For floats, you'd just need to add the decimal part to 5. This will work for any number:
def no_recurse(value)
[value, 5 + value % 1].max
end
no_recurse(4.5)
# 5.5
no_recurse(5.5)
# 5.5
no_recurse(6)
# 6
no_recurse(-7)
# 5

ruby how could i make this factorization recursive till i end with a binary number?

i have this code, basically first i factorize for example the number 28 to:
[2,2,7]
and then i make a list of prime numbers and find the index of each factor in that list, so 2 is prime number with index 0 and 7 prime number with index 2 so it ends up like this:
[[0],[0],[2]]
with which another recursion would be:
[[0],[0],[[0]]]
which tranlated to binary would be:
1101101110111
but im stuck on this:
require 'prime'
def f(n)
Prime.prime_division(n).flat_map { |factor, power| [factor] * power }
end
n=rand(10000)
puts n
f=f (n)
require 'prime'
#list=Prime.take(10000)
g=[]
j=0
f.each do |j|
if j>10
i=f(#list.index(j))
g.push i
i=[]
else
g.push j
end
end
print g
You want to learn, so I won't do all the work for you.
Step 1
Please write those 3 methods :
def get_factors(integer)
# return an Array of Integers:
# get_factors(28) -> [2,2,7]
end
def get_factor_index(prime)
# return the index of prime in Prime.all :
# 2 -> 0
# 7 -> 2
end
def array_to_binary(nested_array)
# convert nested_array (with 0s in leaves) to binary
# [[0],[0],[[0]]] -> "1101101110111"
# Hint : Use Array#to_s, and then String#gsub 3 times to convert ',' to '', and '[' or ']' to 1
end
and come back once you're done. We'll work on the recursion.
Step 2
I modified a bit your answer just a bit. To make it clearer, I tried to use different names for variables and methods. Also, the last line of a method is returned automatically by Ruby. You don't need to define an extra variable. Methods could probably be written more efficiently but I didn't want you to not recognize your code.
Your get_factor_index does more than what I asked for BTW. I'm not sure we can use it like this :
require "prime"
def get_factors(integer)
Prime.prime_division(integer)
end
def nested_array(factors)
factors.flat_map { |factor, power| [factor] * power }
end
def get_factor_index(nested_array)
list=Prime.take(10000)
temp=[]
nested_array.each do |i|
p = list.index(i)
temp.push(p)
end
temp
end
def array_to_binary(array)
temp=array.to_s
temp=temp.gsub("[","1")
temp=temp.gsub("]","1")
temp=temp.gsub(",","")
temp.gsub(" ","")
end
Now, please write a method that uses all the above ones, converting 512 to "10000000001". I'm not sure it's the correct answer, but we'll work on that later.
Also, try this method on 20 (not 28!) and see what you get. Using the above methods, you could try to manually tailor a way to get [[0],[0],[2]]. It's not a problem if it just works for 20 at first.
If you're feeling adventurous, try to get [[0],[0],[[0]]] with the above methods.

Callback after every `each` iteration when `next` is called

I want to run some code after every iteration of each. Is there a way to do this without repeating the code? I tried this:
(1..10).each do |n|
continue = Proc.new {
puts "ended #{n}"
next
}
continue.call if n == 2
puts n
continue.call
end
but it didn't work.
In my actual code, I have lots of next calls. That's why it's unpractical to call a method every time I call next.
Approach 1
Define the contents of the loop in a method that you call from the loop. You can put an ensure block in the method. That way, your method can use return anywhere you want to move onto the next iteration, but you still guarantee you execute the ensure code:
def doit(x)
return if x == 2
puts "I like the number #{x}"
ensure
puts "LOOP"
end
[1,2,3,4].each{|x| doit(x)}
results in
I like the number 1
LOOP
LOOP
I like the number 3
LOOP
I like the number 4
LOOP
Approach 2
Similar to approach 1, but allows you reuse the "callback" code for different concerns. It also keeps you using next instead of return. This is to define a method that yields and then does other stuff:
def ensure_LOOP(x)
yield
puts "LOOP"
end
[1,2,3,4].each do |x|
ensure_LOOP(x) do
next if x == 2
puts "I really like the number #{x}"
end
end
Results in
I really like the number 1
LOOP
LOOP
I really like the number 3
LOOP
I really like the number 4
LOOP
And
[1,2,3,4].each do |x|
ensure_LOOP(x) do
next unless x == 2
puts "I don't like the number #{x}"
end
end
results in
LOOP
I don't like the number 2
LOOP
LOOP
LOOP
As I understand the question, you don't want anything executed after continue.call if n==2. If that's correct, you could use the control expression next with an argument.
def m(n)
puts "Only #{n} more days!"
end
(1..6).each do |n|
next m(n) if n==3
puts n
m(n)
end
1
Only 1 more days!
2
Only 2 more days!
Only 3 more days!
4
Only 4 more days!
5
Only 5 more days!
6
Only 6 more days!
Just call it within the each loop?
(1..10).each do |n|
puts n
puts "ended #{n}"
end
The code you provided actually does run, and outputs the following:
1
ended 1
ended 2
2
ended 2
3
ended 3
4
ended 4
5
ended 5
6
ended 6
7
ended 7
8
ended 8
9
ended 9
10
ended 10
As you can see, the Proc gets called twice for the number 2, as your if condition passes in that case and calls the Proc.
Stepping back, defining a method outside the context of the iteration is probably a better choice. It will make the code easier to read and avoid redefining the Proc each time the each block executes.
That said, technically what you have here seems to run okay.

What does ":*" (colon-star) mean in Ruby?

Looking up how to calculate the factorial of a number I came across this code:
(1..5).inject(:*) || 1 # => 120
What is the (:*) || 1 doing?
How does it compare to this line of code (1..5).inject(1) { |x, y| x * y } # => 120, which uses .inject to achieve similar functionality?
Colon-star in itself doesn't mean anything in Ruby. It's just a symbol and you can pass a symbol to the inject method of an enumerable. That symbol names a method or operator to be used on the elements of the enumerable.
So e.g.:
(1..5).inject(:*) #=> 1 * 2 * 3 * 4 * 5 = 120
(1..5).inject(:+) #=> 1 + 2 + 3 + 4 + 5 = 15
The || 1 part means that if inject returns a falsey value, 1 is used instead. (Which in your example will never happen.)
test.rb:
def do_stuff(binary_function)
2.send(binary_function, 3)
end
p do_stuff(:+)
p do_stuff(:*)
$ ruby test.rb
5
6
If you pass a method name as a symbol, it can be called via send. This is what inject and friends are doing.
About the || part, in case the left hand side returns nil or false, lhs || 1 will return 1
It's absolutely equal. You may use each way, up to your taste.

Equivalent of "continue" in Ruby

In C and many other languages, there is a continue keyword that, when used inside of a loop, jumps to the next iteration of the loop. Is there any equivalent of this continue keyword in Ruby?
Yes, it's called next.
for i in 0..5
if i < 2
next
end
puts "Value of local variable is #{i}"
end
This outputs the following:
Value of local variable is 2
Value of local variable is 3
Value of local variable is 4
Value of local variable is 5
=> 0..5
next
also, look at redo which redoes the current iteration.
Writing Ian Purton's answer in a slightly more idiomatic way:
(1..5).each do |x|
next if x < 2
puts x
end
Prints:
2
3
4
5
Inside for-loops and iterator methods like each and map the next keyword in ruby will have the effect of jumping to the next iteration of the loop (same as continue in C).
However what it actually does is just to return from the current block. So you can use it with any method that takes a block - even if it has nothing to do with iteration.
Ruby has two other loop/iteration control keywords: redo and retry.
Read more about them, and the difference between them, at Ruby QuickTips.
I think it is called next.
Use next, it will bypass that condition and rest of the code will work.
Below i have provided the Full script and out put
class TestBreak
puts " Enter the nmber"
no= gets.to_i
for i in 1..no
if(i==5)
next
else
puts i
end
end
end
obj=TestBreak.new()
Output:
Enter the nmber
10
1
2
3
4
6
7
8
9
10
Use may use next conditionally
before = 0
"0;1;2;3".split(";").each.with_index do |now, i|
next if i < 1
puts "before it was #{before}, now it is #{now}"
before = now
end
output:
before it was 0, now it is 1
before it was 1, now it is 2
before it was 2, now it is 3

Resources