Passing a block to a method recursively in ruby
Asked Answered
B

2

5
def bubble_sort_by nums
  do_it_again = false
  nums[0...-1].each_with_index do |item, index|
    if yield(nums[index], nums[index + 1]) > 0
      nums[index], nums[index + 1] = nums[index + 1], nums[index]
      do_it_again = true
    end
  end
  bubble_sort_by nums if do_it_again
  nums
end

bubble_sort_by(["hi","hello","hey"]) do |left,right|
  right.length - left.length
end

Program does a bubble sort based on a block. In this case, the block sorts by length. So, I get a local jump error. Took me a bit, but I figured it out. When I call the method recursively, I'm not giving it the block. But how do I do that?

Blubberhead answered 1/10, 2014 at 7:48 Comment(0)
C
5

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
Collarbone answered 1/10, 2014 at 8:15 Comment(0)
V
3

yield + block_given solution is an one-off thing, you cannot use it in recursive calls without explicitly passing &block or a Proc(a closure) as a argument, though it yields better performance empirically.

Here is some dummy code(customized version of map function) to do recursive calls

passing a Proc as a normal object

def mymap(xs, f)
  if xs.empty? 
    [] 
  else
    hd, *tl = xs
    [f.call(hd)]+ mymap(tl,f)
  end  
end
mymap([1,2,3], lambda {|x| x*2})

passing optinal &block

def mymmap(xs, &block)
  if xs.empty? 
    [] 
  else
    hd, *tl = xs
    [block.call(hd)]+ mymmap(tl, &block) #here yield(hd) will do as well
  end  
end
mymmap([1,2,3]){|x| 2*x} #notice the calling manner is different from the above 
Vilipend answered 29/7, 2017 at 4:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.