0

I have an array of hashes with the information below. I am trying to get the largest, smallest, and average for "timeAsleep". I have tried the answers from these questions, but it doesn't seem to work.

Find the largest value for an array of hashes with common keys?

Finding the element of a Ruby array with the maximum value for a particular attribute

rails select maximum value from array of hash

Here is the array of hashes

{"id"=>"1", "userId"=>"1", "day"=>"2015-12-05", "startTime"=>"2015-12-05T07:49:30.000Z", "endTime"=>"2015-12-05T15:56:30.000Z", "tzOffset"=>"-08:00", "source"=>"misfit", "mainSleep"=>true, "timeAsleep"=>478, "timeAwake"=>9, "efficiency"=>0, "timeToFallAsleep"=>0, "timeAfterWakeup"=>0, "numberOfWakeups"=>1, "timeInBed"=>0, "createdAt"=>"2015-12-05T21:59:24.935Z", "updatedAt"=>"2015-12-05T21:59:24.935Z", "humanId"=>"1"}
{"id"=>"2", "userId"=>"2", "day"=>"2015-12-04", "startTime"=>"2015-12-04T07:02:30.000Z", "endTime"=>"2015-12-04T14:59:30.000Z", "tzOffset"=>"-08:00", "source"=>"misfit", "mainSleep"=>true, "timeAsleep"=>471, "timeAwake"=>6, "efficiency"=>0, "timeToFallAsleep"=>0, "timeAfterWakeup"=>0, "numberOfWakeups"=>1, "timeInBed"=>0, "createdAt"=>"2015-12-04T16:41:44.198Z", "updatedAt"=>"2015-12-04T16:41:44.198Z", "humanId"=>"2"}
{"id"=>"3", "userId"=>"3", "day"=>"2015-12-03", "startTime"=>"2015-12-03T06:02:32.000Z", "endTime"=>"2015-12-03T13:38:32.000Z", "tzOffset"=>"-08:00", "source"=>"misfit", "mainSleep"=>true, "timeAsleep"=>434, "timeAwake"=>22, "efficiency"=>0, "timeToFallAsleep"=>0, "timeAfterWakeup"=>0, "numberOfWakeups"=>2, "timeInBed"=>0, "createdAt"=>"2015-12-03T15:35:42.903Z", "updatedAt"=>"2015-12-03T15:35:42.903Z", "humanId"=>"3"}
{"id"=>"4", "userId"=>"4", "day"=>"2015-12-02", "startTime"=>"2015-12-02T09:17:33.000Z", "endTime"=>"2015-12-02T15:27:33.000Z", "tzOffset"=>"-08:00", "source"=>"misfit", "mainSleep"=>true, "timeAsleep"=>370, "timeAwake"=>0, "efficiency"=>0, "timeToFallAsleep"=>0, "timeAfterWakeup"=>0, "numberOfWakeups"=>0, "timeInBed"=>0, "createdAt"=>"2015-12-03T04:00:02.050Z", "updatedAt"=>"2015-12-03T04:00:02.050Z", "humanId"=>"4"}
{"id"=>"5", "userId"=>"5", "day"=>"2015-12-01", "startTime"=>"2015-12-01T05:45:36.000Z", "endTime"=>"2015-12-01T13:50:36.000Z", "tzOffset"=>"-08:00", "source"=>"misfit", "mainSleep"=>true, "timeAsleep"=>485, "timeAwake"=>0, "efficiency"=>0, "timeToFallAsleep"=>0, "timeAfterWakeup"=>0, "numberOfWakeups"=>0, "timeInBed"=>0, "createdAt"=>"2015-12-01T17:50:20.168Z", "updatedAt"=>"2015-12-01T17:50:20.168Z", "humanId"=>"5"}
{"id"=>"6", "userId"=>"6", "day"=>"2015-11-30", "startTime"=>"2015-11-30T05:57:38.000Z", "endTime"=>"2015-11-30T14:23:38.000Z", "tzOffset"=>"-08:00", "source"=>"misfit", "mainSleep"=>true, "timeAsleep"=>499, "timeAwake"=>7, "efficiency"=>0, "timeToFallAsleep"=>0, "timeAfterWakeup"=>0, "numberOfWakeups"=>1, "timeInBed"=>0, "createdAt"=>"2015-11-30T16:18:38.276Z", "updatedAt"=>"2015-11-30T16:18:38.276Z", "humanId"=>"6"}
Community
  • 1
  • 1
user2974739
  • 619
  • 1
  • 7
  • 20
  • 1
    Can you show us what you've tried so far? (some code written by you, to help you find the bug and suggest you how to improve it) – Oscar Mederos Dec 08 '15 at 00:40
  • sleeps.max_by{|x| x[:timeAsleep]} this always returns the first value – user2974739 Dec 08 '15 at 00:41
  • because you're accessing to `x[:timeAsleep]` but keys in your hash are not symbols, but strings, so `x['timeAsleep']` should work. – Oscar Mederos Dec 08 '15 at 00:43
  • thanks! works. How do I get average? – user2974739 Dec 08 '15 at 00:45
  • 1
    Welcome to Stack Overflow. When supplying data like your "array of hashes", it needs to be syntactically correct. What you supplied isn't an array of hashes. Paste that into IRB and you'll see. We also expect you to provide us with an example of the code you've written toward solving the problem. Stack Overflow isn't a "write code for me" site, it's a "I need help debugging a problem with the code I wrote" site. Please read "[ask]". As is, we have no idea what you've tried, and would write code that is totally unrelated to anything you wrote. – the Tin Man Dec 08 '15 at 01:12
  • 1
    Is it really necessary to have an example with hashes having 18 keys when you want statistics for the values of just one key? How about an example with, say, two keys? – Cary Swoveland Dec 08 '15 at 03:53
  • Thank you for the comments. I'll keep this in mind when posting questions. – user2974739 Dec 08 '15 at 17:02

3 Answers3

3

Here is how you can do it:

array.max_by {|x| x['timeAsleep']} # max
array.min_by {|x| x['timeAsleep']} # min
array.map {|x| x['timeAsleep']}.reduce(:+) / array.size.to_f # average

You can read about map and reduce on the documentation

Oscar Mederos
  • 29,016
  • 22
  • 84
  • 124
  • Map is redundant in the last expression: `array.reduce(0) {|m,x| m + x['timeAsleep']} / array.size` – joanbm Dec 08 '15 at 01:44
  • This will also round the average via integer division; you could do `array.reduce(0) { |m,x| m + x['timeAsleep'] }.to_f / array.size` if you want the exact (decimal) average. – etdev Dec 08 '15 at 02:47
  • `array.max_by` and `array.min_by` return hashes, not values. – Cary Swoveland Dec 08 '15 at 05:11
0
arr = [
  {"id"=>"1", "timeAsleep"=>478, "timeAwake"=>9},
  {"id"=>"2", "timeAsleep"=>471, "timeAwake"=>6},
  {"id"=>"3", "timeAsleep"=>434, "timeAwake"=>22},
  {"id"=>"4", "timeAsleep"=>370, "timeAwake"=>0},
  {"id"=>"5", "timeAsleep"=>485, "timeAwake"=>502},
  {"id"=>"6", "timeAsleep"=>499, "timeAwake"=>7}] 

sleep_times = arr.map { |h| h["timeAsleep"] }
  #=> [478, 471, 434, 370, 485, 499]

Min and max value for timeAsleep

sleep_times.minmax
  #=> [370, 499] 

Mean for timeAsleep

sleep_times.reduce(:+).fdiv(arr.size).round(1)
  #=> 456.2

Max value all keys with numeric values

(I'm not sure if you wanted this.)

arr.map { |h| h.values.select { |v| v.kind_of?(Numeric) }.max }.max
  #=> 502
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
0

A more efficient way will be to sort the array of hashes once instead of finding max/min etc.

array = array_hash.sort_by {|k| k["timeAsleep"] }

Then you can just retrieve the respective hashes from the sorted array

puts "Hash with Smallest timeAsleep", array[0]
puts "Hash with Largest timeAsleep", array[array.length-1]

if ((array.length % 2) == 0)
    puts "Hash with Average timeAsleep", array[(array.size/2)-1]
else
    puts "Hash with Average timeAsleep", array[(array.size/2)]
end
Linju
  • 335
  • 3
  • 9