rubyrspecperformancetest-first

having issues with finding the average run time of a block


I am currently doing Test First programming and am stuck on the 06_performance monitor problem located at http://testfirst.org/live/learn_ruby/performance_monitor I found a similar thread on stackoverflow but I still am not understanding the problem. I am failing the last two tests on finding the average run time of multiple blocks. My code so far is:

def measure(i=1)
  if i>1
    i.times do 
      yield
    end
  else
    x = Time.now
    yield
    elapsed_time = Time.now - x
  end
end

I am very confused at what the test is trying to do. So far this is what I think I have to do:

I believe the task is to find how long certain blocks take to run. However, I am not sure exactly why this code is even working for the first few tests. And also I am having issues with knowing exactly what the yield statement is returning. I would really appreciate it if someone could walk me through the process of solving this problem so that I understand the solution.


Solution

  • Your method is mostly ok so far, except you don't need to branch out i == 1 from i > 1{ 1.times { yield } is functionally equivalent to just calling yield.

    yield doesn't return anything on its own. It is a keyword that indicates the block given to the method should be called, and can optionally be fed variables that would in turn get passed to the block, e.g:

    class String
      def each_character_in_reverse_order
        each_char.to_a.reverse_each do |char|
          yield char
        end
      end
    end
    
    "hello".each_character_in_reverse_order do |c|
      puts c.upcase
    end
    
    #=> 
    # O
    # L
    # L
    # E
    # H
    

    In the case of the tests you've linked to, the return values of the blocks are complete inconsequential, as they are only interested in how long it takes to run the block. But as you can see in the example above, the yield keyword can be embedded in a block of its own (reverse_each do ... end), which means you can wrap other behavior around it each time the given block is called:

    1.times do
      start_time = Time.now
      yield
      elapsed = Time.now - start_time
    end
    

    In this case, you want to return values from the times do ... end block so you can average together the runtimes of the given block, so you need to find a way to store these in an array, average them together, and return that average as the result of your measure method. Keep in mind that you can average a single value to return that value, so you don't need different behavior for single runs vs. multiple runs. Hint - you can call n.times.map do ... end to return an array directly from the times block, without having to instantiate one explicitly.