5

I have the following method in my Array class:

class Array
  def avg
    if partial_include?(":")
      avg_times
    else
      blank? and 0.0 or (sum.to_f/size).round(2)
    end
  end

  def avg_times
    avg_minutes = self.map do |x|
      hour, minute = x.split(':')
      total_minutes = hour.to_i * 60 + minute.to_i
    end.inject(:+)/size
    "#{avg_minutes/60}:#{avg_minutes%60}"
  end

  def partial_include?(search_term)
    self.each do |e|
      return true if e[search_term]
    end
    return false
  end
end

This works great with arrays of regular numbers, but there could instances where I have an array of times.

For example: [18:35, 19:07, 23:09]

Anyway to figure out the average of an array of time objects?

8
  • 4
    Is that strings in that format or a datetime object? Commented Oct 9, 2013 at 18:54
  • You could call to_i and get the sum and divide. Would be faster if you subtract an offset first so you're not working with Bignums Commented Oct 9, 2013 at 18:54
  • Are they ever mixed, or is it always numbers or times never both? Commented Oct 9, 2013 at 18:54
  • @hirolau - They are strings Commented Oct 9, 2013 at 18:55
  • 1
    As the code is now you can replace partial_include?(":") with self.first[':'] and then remove the partial_include? method. Commented Oct 9, 2013 at 20:12

2 Answers 2

4

So you need do define a function that can calculate the average of times formatted as strings. Convert the data to minutes, avg the total minutes and then back to a time.

I would do it something like this:

a =  ['18:35', '19:07', '23:09']

def avg_of_times(array_of_time)
  size = array_of_time.size
  avg_minutes = array_of_time.map do |x|
    hour, minute = x.split(':')
    total_minutes = hour.to_i * 60 + minute.to_i
  end.inject(:+)/size
  "#{avg_minutes/60}:#{avg_minutes%60}"
end

p avg_of_times(a) # = > "20:17"

Then when you call you function you check if any/all items in your array is formatted as a time. Maybe using regexp.

Sign up to request clarification or add additional context in comments.

6 Comments

When I run that, my dumped out value is "847/45:148/3" -- I updated my question with a new version of the my Array class
This works fine for me with latest version of Ruby. If you skip the last line, do you get the correct amount of minutes? (1217 in my example above?) If so, just write your own "convert minutes to hours and minutes" line.
hmm... yeah I am running ruby 1.9.3
What about changing the last line to "%s:%s" % avg_minutes.divmod(60) ruby-doc.org/core-1.9.3/Numeric.html#method-i-divmod
Thanks! that worked like a charm! what's weird is I had another developer who is running Ruby 1.9.3-p329 and it worked as expected
|
1

Average the Hours and Minutes Separately

Here's a simple method that we're using:

def calculate_average_of_times( times )
  hours   = times.collect{ |time| time.split( ":" ).first.to_i }  # Large Arrays should only
  minutes = times.collect{ |time| time.split( ":" ).second.to_i } # call .split 1 time.

  average_hours   = hours.sum / hours.size
  average_minutes = ( minutes.sum / minutes.size ).to_s.rjust( 2, '0' ) # Pad with leading zero if necessary.

  "#{ average_hours }:#{ average_minutes }"
end

And to show it working with your provided Array of 24-hour times, converted to Strings:

calculate_average_of_times( ["18:35", "19:07", "23:09"] )
#=> "20:17"

Thanks to @matt-privman for the help and inspiration on this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.