Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do I get a recursive method to take a, non argument, block and run it on each recurrent call?

I’m trying to write a recursive binary tree depth first, pre-order, traversal method and have it also work when it’s passed a block. But I’m struggling to work out how to get it to use the passed block from the initial call on each internal recurrent call to itself. The code I’ve currently written is:

  def pre_order(node = @root, values = [])
    return values if node.nil?
    block_given? ? values << yield(node.value) : values << node.value
    pre_order(node.left, values) if node.left
    pre_order(node.right, values) if node.right
    values
  end

Calling #pre_order on my test tree object without passing a block returns this correct output; [7, 1, 4, 65, 13, 97]. However when I call #pre_order and pass it a block, e.g.; #pre_order { |value| value * 2 } the result I get, vs the result I’m aiming for is;

Result from above code; [14, 1, 4, 65, 13, 97]
Result I’m aiming for; [14, 2, 8, 130, 26, 194]

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I suppose the best way might be to save the initially passed block in a variable somehow so that it can be used it again on the recursive method calls on lines 4 & 5, without it being lost or needing to be reset on each method call. How might this be done? (I have a feeling I’m in Proc territory here, and am researching this further, but would appreciate some guidance on the ‘Ruby way‘ of this.)

>Solution :

You have to define the block argument explicitly and pass it along:

def pre_order(node = @root, values = [], &block)
  # ...
  pre_order(node.left, values, &block) if node.left
  pre_order(node.right, values, &block) if node.right
  # ...
end

With an explicit block argument, you could also replace yield(node.value) with a more explicit block.call(node.value) or the shorthand block.(node.value) syntax. (note the . before the parentheses)

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading