Group JSON by data?

arrays, json, ruby, ruby-on-rails

Solution

The magic you want is `Enumerable#group_by`:

require 'json'
all = JSON.parse(DATA.read)['events']['event']
all.group_by{ |h| [h['city'],h['state'],h['country']] }.each do |loc,events|
  puts "'#{loc.join(',')}': #{events.length} event#{:s if events.length!=1}"
  print "--> "
  puts events.map{ |e| e['status'] }.join(', ')
end

#=> 'Birmingham,AL,US': 3 events
#=> --> Delivered, Out For Delivery, Arrival Scan
#=> 'Doraville,GA,US': 2 events
#=> --> Departure Scan, Arrival Scan
#=> 'Spartanburg,SC,US': 2 events
#=> --> Departure Scan, Arrival Scan
#=> 'Greensboro,NC,US': 2 events
#=> --> Departure Scan, Origin Scan
#=> ',,US': 1 event
#=> --> Billing Information Received

Note that, in the above, `loc` is the three-element array returned from the block evaluated by `group_by`, and `events` is an array of all items in the same group.

Problem

I've got the following JSON data: ``` { "events": { "event": [ { "city":"Birmingham", "state":"AL", "country":"US", "lat":"33.5206608", "lng":"-86.80249", "status":"Delivered", "occured_at":"2012-04-06 14:17:00 UTC" }, { "city":"Birmingham", "state":"AL", "country":"US", "lat":"33.5206608", "lng":"-86.80249", "status":"Out For Delivery", "occured_at":"2012-04-06 04:44:00 UTC" }, { "city":"Birmingham", "state":"AL", "country":"US", "lat":"33.5206608", "lng":"-86.80249", "status":"Arrival Scan", "occured_at":"2012-04-05 19:07:00 UTC" }, { "city":"Doraville", "state":"GA", "country":"US", "lat":"33.8981579", "lng":"-84.2832564", "status":"Departure Scan", "occured_at":"2012-04-05 17:08:00 UTC" }, { "city":"Doraville", "state":"GA", "country":"US", "lat":"33.8981579", "lng":"-84.2832564", "status":"Arrival Scan", "occured_at":"2012-04-05 11:15:00 UTC" }, { "city":"Spartanburg", "state":"SC", "country":"US", "lat":"34.9495672", "lng":"-81.9320482", "status":"Departure Scan", "occured_at":"2012-04-05 08:42:00 UTC" }, { "city":"Spartanburg", "state":"SC", "country":"US", "lat":"34.9495672", "lng":"-81.9320482", "status":"Arrival Scan", "occured_at":"2012-04-05 08:21:00 UTC" }, { "city":"Greensboro", "state":"NC", "country":"US", "lat":"36.0726354", "lng":"-79.7919754", "status":"Departure Scan", "occured_at":"2012-04-05 04:45:00 UTC" }, { "city":"Greensboro", "state":"NC", "country":"US", "lat":"36.0726354", "lng":"-79.7919754", "status":"Origin Scan", "occured_at":"2012-04-05 00:11:00 UTC" }, { "city":null, "state":null, "country":"US", "status":"Billing Information Received", "occured_at":"2012-04-04 18:20:27 UTC" } ] } } ``` What I need to do is group the data by a combination of city, state and country, but still return the data from each item. So for instance, group by "Birmingham, AL, US" but still be able to iterate through the `status`'s of each event (ie. Delivered, Out for Delivery, Arrival Scan) with that.

Original source

Related problems