Reputation: 601
I want to group events by their days. Prefact:
Available days are 1,2,3,4,5,6,7
One event can not contain duplicates. e.g [1,1,2,3]
Setup is Ruby 1.9.2 with Rails 3.2
An event is containing like 8-10 more attributes(unnecessary to include in example, but should be considered, these attributes should still be there after grouping.) In other words the event objects should not be altered only grouped as is.
Consider an array with objects:
events = [
{
:name => "event1",
:days => [1,2,3,4,5]
},
{
:name => "event2",
:days => [1,4,5]
},
{
:name => "event3",
:days => [1]
},
{
:name => "event4",
:days => [2]
},
{
:name => "event5",
:days => [3]
},
{
:name => "event6",
:days => [4]
},
{
:name => "event7",
:days => [5]
},
{
:name => "event8",
:days => [1,2,3]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event10",
:days => [1,2]
},
{
:name => "event11",
:days => [1,2,3,4,5]
}
]
To be grouped an event must have at least 3 days. And these days should be in numerically order.
Example(should be grouped): [1,2,3]
Example(should not be grouped): [1,4,5]
Events that's not suitable for grouping should be placed in each day they contain.
Example: [1,4,5] should be placed in 1,4 and 5.
The desired result of events array above:
[
{
:heading => "1",
:events => [
{
:name => "event3",
:days => [1]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event10",
:days => [1,2]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "2",
:events => [
{
:name => "event4",
:days => [2]
},
{
:name => "event10",
:days => [1,2]
}
]
},
{
:heading => "3",
:events => [
{
:name => "event5",
:days => [3]
}
]
},
{
:heading => "4",
:events => [
{
:name => "event6",
:days => [4]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "5",
:events => [
{
:name => "event7",
:days => [5]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "1-3",
:events => [
{
:name => "event8"
}
]
},
{
:heading => "1.5",
:events => [
{
:name => "event1"
},
{
:name => "event11"
}
]
}
]
It is very advanced Ruby here. Maybe too advanced for me, everything I've tried ends up missing one part of the equation. But hey it's Ruby, it shouldn't be that hard?
EDIT: Updated example with clarification and corrected expected output
Upvotes: 0
Views: 155
Reputation: 146093
require 'pp'
pp(events.inject(Hash.new { |h, k| h[k] = [] }) do |m, e|
days = e[:days]
event = { :name => e[:name] }
if days.size >= 3 && days.last - days.first + 1 == days.size
m["%d-%d" % [days.first, days.last]] << event
else
days.each { |d| m[d.to_s] << event }
end
m
end)
Upvotes: 2
Reputation: 1484
I would modify DigitalRoss's answer slightly. I would change
if days.size >= 3 && days.last - days.first + 1 == days.size
to
if days.size >= 3 && (days.first..days.last).to_a == days
This will catch [1,1,3,4]...
It would also be wise to sort the days array before testing!
Upvotes: 1