Reputation: 117
Here's an object I'm working with in Ruby. It's a bunch of events sorted by date, but I want to nest the object one level deeper when there are two or more with the same event_type next to each other in the object.
@events = [
{ :id => 1, :event_type => "B", :created_at => "2013-09-30 14:44:24 UTC"},
{ :id => 2, :event_type => "A", :created_at => "2013-09-29 14:44:24 UTC"},
{ :id => 3, :event_type => "A", :created_at => "2013-09-28 14:44:24 UTC"},
{ :id => 4, :event_type => "C", :created_at => "2013-09-27 14:44:24 UTC"},
{ :id => 5, :event_type => "C", :created_at => "2013-09-26 14:44:24 UTC"},
{ :id => 6, :event_type => "A", :created_at => "2013-09-25 14:44:24 UTC"}
]
I'm looking to turn it into this:
@events = [
{ :id => 1, :event_type => "B", :created_at => "2013-09-30 14:44:24 UTC"},
{ :grouped_events => [
{ :id => 2, :event_type => "A", :created_at => "2013-09-29 14:44:24 UTC"},
{ :id => 3, :event_type => "A", :created_at => "2013-09-28 14:44:24 UTC"}
]
},
{ :grouped_events => [
{ :id => 4, :event_type => "C", :created_at => "2013-09-27 14:44:24 UTC"},
{ :id => 5, :event_type => "C", :created_at => "2013-09-26 14:44:24 UTC"}
]
},
{ :id => 6, :event_type => "A", :created_at => "2013-09-25 14:44:24 UTC"}
]
I need the overall object to keep the nested objects sorted by date, but if there are 2 or more events clustered together, I want them turned into an array, as seen by the sample output. It seems like a simple problem, but I can't seem to figure it out.
Upvotes: 1
Views: 178
Reputation: 4847
To keep order use chunk method of Enumerable
:
@events = [
{ :id => 1, :event_type => "B", :created_at => "2013-09-30 14:44:24 UTC"},
{ :id => 1, :event_type => "A", :created_at => "2013-09-29 14:44:24 UTC"},
{ :id => 1, :event_type => "A", :created_at => "2013-09-28 14:44:24 UTC"},
{ :id => 1, :event_type => "C", :created_at => "2013-09-27 14:44:24 UTC"},
{ :id => 1, :event_type => "C", :created_at => "2013-09-26 14:44:24 UTC"},
{ :id => 1, :event_type => "A", :created_at => "2013-09-25 14:44:24 UTC"}
]
p @events.chunk{|el| el[:event_type]}.map{|gr| gr[1]}
Output:
#=> [[{:id=>1, :event_type=>"B", :created_at=>"2013-09-30 14:44:24 UTC"}],
#=> [{:id=>1, :event_type=>"A", :created_at=>"2013-09-29 14:44:24 UTC"},
#=> {:id=>1, :event_type=>"A", :created_at=>"2013-09-28 14:44:24 UTC"}],
#=> [{:id=>1, :event_type=>"C", :created_at=>"2013-09-27 14:44:24 UTC"},
#=> {:id=>1, :event_type=>"C", :created_at=>"2013-09-26 14:44:24 UTC"}],
#=> [{:id=>1, :event_type=>"A", :created_at=>"2013-09-25 14:44:24 UTC"}]]
Or, if you like to have arrays only when there 2 or more elements try this:
p @events
.chunk{|el| el[:event_type]}
.flat_map{|gr| gr[1].length == 1 ? gr[1] : [gr[1]]}
Output will be
#=> [
#=> {:id=>1, :event_type=>"B", :created_at=>"2013-09-30 14:44:24 UTC"},
#=> [{:id=>1, :event_type=>"A", :created_at=>"2013-09-29 14:44:24 UTC"},
#=> {:id=>1, :event_type=>"A", :created_at=>"2013-09-28 14:44:24 UTC"}],
#=> [{:id=>1, :event_type=>"C", :created_at=>"2013-09-27 14:44:24 UTC"},
#=> {:id=>1, :event_type=>"C", :created_at=>"2013-09-26 14:44:24 UTC"}],
#=> {:id=>1, :event_type=>"A", :created_at=>"2013-09-25 14:44:24 UTC"}
#=> ]
Update
You change output format on the fly :)
For your last variant try this:
p @events
.chunk{|el| el[:event_type]}
.flat_map{|gr|
gr[1].length == 1 ? gr[1] : {:grouped_events => gr[1]}
}
Upvotes: 2
Reputation: 13901
What about
p @events.group_by{|item| item[:event_type]}.values #=>
# [[{:id=>1, :event_type=>"B", :created_at=>"2013-09-30 14:44:24 UTC"}],
# [{:id=>1, :event_type=>"A", :created_at=>"2013-09-29 14:44:24 UTC"},
# {:id=>1, :event_type=>"A", :created_at=>"2013-09-28 14:44:24 UTC"},
# {:id=>1, :event_type=>"A", :created_at=>"2013-09-25 14:44:24 UTC"}],
# [{:id=>1, :event_type=>"C", :created_at=>"2013-09-27 14:44:24 UTC"},
# {:id=>1, :event_type=>"C", :created_at=>"2013-09-26 14:44:24 UTC"}]]
Upvotes: 0