user2974739
user2974739

Reputation: 639

Calculate average time from array of hashes

I am trying to calculate the average time from an array of hashes. Here's the array.

array = [
  {"startTime"=>"2015-12-05T07:49:30.000Z", "endTime"=>"2015-12-05T15:56:30.000Z"},
  {"startTime"=>"2015-12-04T07:02:30.000Z", "endTime"=>"2015-12-04T14:59:30.000Z"},
  {"id"=>"5660614e8a3b090700bad845", "userId"=>"55cd59542d98600100397c12", "day"=>"2015-12-03", "startTime"=>"2015-12-03T06:02:32.000Z", "endTime"=>"2015-12-03T13:38:32.000Z"},
  {"startTime"=>"2015-12-02T09:17:33.000Z", "endTime"=>"2015-12-02T15:27:33.000Z"},
  {"startTime"=>"2015-12-01T05:45:36.000Z", "endTime"=>"2015-12-01T13:50:36.000Z"}
]

I'm trying to get the average startTime and endTime. Here is what I have tried so far.

avg = Time.at(array.map {|x| x['startTime']}.reduce(:+).to_f / array.size.to_i)

The result I get is 1969-12-31 16:06:43 -0800. This is not correct.

Upvotes: 1

Views: 229

Answers (2)

Andrey Deineko
Andrey Deineko

Reputation: 52357

require 'time'

array = [
  {"startTime"=>"2015-12-05T07:49:30.000Z", "endTime"=>"2015-12-05T15:56:30.000Z"},
  {"startTime"=>"2015-12-04T07:02:30.000Z", "endTime"=>"2015-12-04T14:59:30.000Z"},
  {"id"=>"5660614e8a3b090700bad845", "userId"=>"55cd59542d98600100397c12", "day"=>"2015-12-03", "startTime"=>"2015-12-03T06:02:32.000Z", "endTime"=>"2015-12-03T13:38:32.000Z"},
  {"startTime"=>"2015-12-02T09:17:33.000Z", "endTime"=>"2015-12-02T15:27:33.000Z"},
  {"startTime"=>"2015-12-01T05:45:36.000Z", "endTime"=>"2015-12-01T13:50:36.000Z"}
]

times = array.map{|el| el['startTime']}.map{|el| Time.parse(el) }
#=> [2015-12-05 07:49:30 UTC, 2015-12-04 07:02:30 UTC, 2015-12-03 06:02:32 UTC, 2015-12-02 09:17:33 UTC, 2015-12-01 05:45:36 UTC]

average_time = Time.at(times.map(&:to_f).inject(:+) / times.size)
#=> 2015-12-03 08:11:32 +0100

Upvotes: 4

Cary Swoveland
Cary Swoveland

Reputation: 110725

require 'time'

keys = ["startTime", "endTime"]
n = array.size
keys.zip(array.map { |h| h.values_at(*keys).map { |d| Time.parse(d).to_f }}.
     transpose.
     map { |a| Time.at(a.reduce(:+)/n) }).to_h
  #=> {"startTime"=>2015-12-02 23:11:32 -0800, "endTime"=>2015-12-03 06:46:32 -0800} 

The steps:

keys = ["startTime", "endTime"]
n = array.size
  #=> 5
a = array.map { |h| h.values_at(*keys).map { |d| DateTime.parse(d).to_time.to_f }}
  #=> [[1449301770.0, 1449330990.0],
  #    [1449212550.0, 1449241170.0],
  #    [1449122552.0, 1449149912.0],
  #    [1449047853.0, 1449070053.0],
  #    [1448948736.0, 1448977836.0]] 

In computing a, the block variable is initially set to the first element of array:

h = array.first
  #=> {"startTime"=>"2015-12-05T07:49:30.000Z", "endTime"=>"2015-12-05T15:56:30.000Z"}     

and the block calculation is performed:

b = h.values_at(*keys)    
  #=> ["2015-12-05T07:49:30.000Z", "2015-12-05T15:56:30.000Z"] 
b.map { |d| Time.parse(d).to_f }
  #=> [1449301770.0, 1449330990.0] 

Other elements of a are calculated similarly.

Continuing with the calculation:

c = a.transpose
  #=> [[1449301770.0, 1449212550.0, 1449122552.0, 1449047853.0, 1448948736.0],
  #    [1449330990.0, 1449241170.0, 1449149912.0, 1449070053.0, 1448977836.0]] 

d = c.map { |a| Time.at(a.reduce(:+)/n) }
  #=> [2015-12-02 23:11:32 -0800, 2015-12-03 06:46:32 -0800] 

The calculation of d is equivalent to:

e = c.map { |a| a.reduce(:+) }
  #=> [7245633461.0, 7245769961.0] 
f = e.map { |t| t/n }
  #=> [1449126692.2, 1449153992.2] 
d = f.map { |t| Time.at(t) }
  #=> [2015-12-02 23:11:32 -0800, 2015-12-03 06:46:32 -0800] 

The last step is to present the result in a hash:

g = keys.zip(d)
  #=> [["startTime", 2015-12-02 23:11:32 -0800], ["endTime", 2015-12-03 06:46:32 -0800]] 
g.to_h
  #=> {"startTime"=>2015-12-02 23:11:32 -0800,
  #    "endTime"=>2015-12-03 06:46:32 -0800} 

Upvotes: 1

Related Questions