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

Advertisements

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]

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)

Leave a ReplyCancel reply