Passing a block to a method recursively in ruby
Passing the block is optional, but here, as you already understood, you need it to make your recursive calls. You just pass the block as an additional parameter:
def bubble_sort_by nums, &comparator
# ...
bubble_sort_by nums, &comparator if do_it_again
# ...
end
What is recursion and how does it work?
A recursive function/method calls itself. For a recursive algorithm to terminate you need a base case (e.g. a condition where the function does not call itself recursively) and you also need to make sure that you get closer to that base case in each recursive call. Let's look at a very simple example:
def countdown(n)
return if n.zero? # base case
puts n
countdown(n-1) # getting closer to base case
end
countdown(5)
5
4
3
2
1
Some problems can be very elegantly expressed with recursion, e.g a lot of mathematical functions are described in a recursive way.
Ruby: recursive method
- The method
reverse_append([],4)
is called - Since
4 >= 0
, thereturn
statement does not get called. - The method
reverse_append([],3)
is called. - Since
3 >= 0
, thereturn
statement does not get called. - The method
reverse_append([],2)
is called. - Since
2 >= 0
, thereturn
statement does not get called. - The method
reverse_append([],1)
is called. - Since
1 >= 0
, thereturn
statement does not get called. - The method
reverse_append([],0)
is called. - Since
0 >= 0
, thereturn
statement does not get called. - The method
reverse_append([],-1)
is called. - Since
-1 < 0
, the array ([]
) is returned. - We pop up one level in our call stack, to where
n = 0
andarr = []
. arr << n
andarr
is returned, so nowarr = [0]
.- We pop up one level in our call stack, to where
n = 1
andarr = [0]
. arr << n
andarr
is returned, so nowarr = [0, 1]
.- We pop up one level in our call stack, to where
n = 2
andarr = [0, 1]
. arr << n
andarr
is returned, so nowarr = [0, 1, 2]
.- We pop up one level in our call stack, to where
n = 3
andarr = [0, 1, 2]
. arr << n
andarr
is returned, so nowarr = [0, 1, 2, 3]
.- We pop up one level in our call stack, to where
n = 4
andarr = [0, 1, 2, 3]
. arr << n
andarr
is returned, so nowarr = [0, 1, 2, 3, 4]
.- Finally, the "top-level" method returns, and we have our final result.
How to write a recursive factorial function in Ruby?
Here's how to write the your code in ruby:
def factorial(n)
return 1 if n == 1
n * factorial(n - 1)
end
factorial(5)
#=> 120
factorial(7)
#=> 5040
Edit for Stefan's comment:
To avoid a SystemStackError
error with large values of n
, use the tail-recursive method. Also Ruby's tailcall
optimization must be enabled.
# before edit
factorial(100_000).to_s.size
#=> stack level too deep (SystemStackError)
To avoid SystemStackError
RubyVM::InstructionSequence.compile_option = {
tailcall_optimization: true,
trace_instruction: false
}
RubyVM::InstructionSequence.new(<<-CODE).eval
def factorial(n, acc = 1)
return acc if n == 1
factorial(n - 1, n * acc)
end
CODE
puts factorial(100_000).to_s.size
#=> 456574
Resource 1
Resource 2
adding array elements using recursion
def parts_sums(ls)
ls.length == 1 ? ls : ([ls.sum] + parts_sums(ls[1..-1]))
end
puts parts_sums([0, 1, 3, 6, 10]).to_s
Ruby + recursive function + defining global variable
The consensus is to avoid global variables as much as possible.
I would either build the collection recursively like this:
def recursive(url)
### ...
result = []
hash["values"].each do |x|
result << x["links"]["self"]["href"]
end
if hash["next"]
result += recursive(hash["next"])
end
result
end
or hand over the collection to the function:
def recursive(url, result = [])
### ...
hash["values"].each do |x|
result << x["links"]["self"]["href"]
end
if hash["next"]
recursive(hash["next"], result)
end
result
end
Either way you can call the function
repo_list = recursive(url)
And I would write it like this:
def recursive(url)
# ...
result = hash["values"].map { |x| x["links"]["self"]["href"] }
result += recursive(hash["next"]) if hash["next"]
result
end
Related Topics
How to Build a Docker Image for a Ruby Project Without Build Tools
How to Transform the Utf8 Chars to Iso8859-1
I Trying to Make a Code That Gives the User a Personal Number After They Have Made an User
How to Link to a Page with Page.Url Without the HTML Extension in Jekyll
Ruby Getting Deeply Nested JSON API Data
How to Reinstall Ruby with Readline Support
How to Make Empty Tags Self-Closing with Nokogiri
Ruby Console Input Halting at 1024 Characters
Mechanize and Ntlm Authentication
Rails Object Based Permission/Authorization Engine
What Is an Eoferror in Ruby File I/O
Deep Convert Openstruct to JSON
Which Global Variable Is for Last Expression