1

I have an array:

array = ["0:00:31", "0:00:52", "0:01:05", "0:00:55", "0:01:33", "0:00:05", "0:00:01", 
      "0:05:10", "0:02:40", "0:03:03", "0:01:33", "0:00:00"]

and I need to average all of the times in the array that are not equal to "0:00:00". "0:00:00" should just be thrown out.

What's the best way to do this? I'm currently looping through the array, removing all of the 0:00:00 values, turning the strings into integers and doing an average - But it seems like a lot of code for what I'm trying to do.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Luigi
  • 5,443
  • 15
  • 54
  • 108

3 Answers3

7
(sz = array.reject    {|t| t == '0:00:00' }).
            map       {|t| Time.parse t   }.
            reduce(0) {|a, t| a += t.to_i }.to_f / sz.size

You want to group these things into functional operations. Reject the stuff you don't need, then act on the rest.

Here, reduce is a viable way to get an array average, and has been answered before.


here is an alternative that is slightly more concise, slightly more cryptic

(sz = array.reject {|t| t == '0:00:00'     }).
            map    {|t| Time.parse(t).to_i }.
            reduce(:+).to_f / sz.size
Community
  • 1
  • 1
New Alexandria
  • 6,951
  • 4
  • 57
  • 77
1

Tweaking NewAlexandria's answer to return average in seconds:

(sz = array.reject    {|t| t == '0:00:00' }).
            map       {|t| t.split(":").inject(0){|product,n| product * 60 + n.to_i} }.
            reduce(0) {|a, t| a += t.to_i }.to_f / sz.size
Larsenal
  • 49,878
  • 43
  • 152
  • 220
0

I am not getting NewAlexandria's answer to work for some reason, here is how I would do it:

def average_of_times(array)
    zero_seconds      = ->x{ x=='0:00:00' }
    covert_to_seconds = ->x do
      hours, minutes, seconds = x.split(':').map(&:to_i)
      hours * 3600 + minutes * 60 + seconds
    end

    seconds = array.reject!(&zero_seconds)
             .map(&covert_to_seconds)
             .reduce(:+) / array.size

    Time.at(seconds).utc.strftime("%H:%M:%S")
end
hirolau
  • 13,451
  • 8
  • 35
  • 47