Front-end sends me a string in which it gets the user's meeting schedule which looks like below:
> payload
=> "Sun 10:00-20:00\nFri 05:00-10:00\nFri 16:30-23:50\nSat 10:00-24:00\nSun 01:00-04:00\nSat 02:00-06:00\nTue 03:30-18:15\nTue 19:00-20:00\nWed 04:25-15:14\nWed 15:14-22:40\nThu 00:00-23:59\nMon 05:00-13:00\nMon 15:00-21:00"
Each line is a substring representing one meeting in the schedule. One string represents whole week. I have to calculate the free slots between meetings (in minutes) and send this information to front-end.
I think to do this I need to change the string to a hash like below:
# first split payload
> splitted_dates = payload.split("\n").map { |date| date.split }
=> [["Sun", "10:00-20:00"], ["Fri", "05:00-10:00"], ["Fri", "16:30-23:50"], ["Sat", "10:00-24:00"], ["Sun", "01:00-04:00"], ["Sat", "02:00-06:00"], ["Tue", "03:30-18:15"], ["Tue", "19:00-20:00"], ["Wed", "04:25-15:14"], ["Wed", "15:14-22:40"], ["Thu", "00:00-23:59"], ["Mon", "05:00-13:00"], ["Mon", "15:00-21:00"]]
# then create a hash with structure { day:, time: }
> schedule_hash = splitted_dates.map { |d| { day: d[0], time: d[1] } }
=> [{:day=>"Sun", :time=>"10:00-20:00"},
{:day=>"Fri", :time=>"05:00-10:00"},
{:day=>"Fri", :time=>"16:30-23:50"},
{:day=>"Sat", :time=>"10:00-24:00"},
{:day=>"Sun", :time=>"01:00-04:00"},
{:day=>"Sat", :time=>"02:00-06:00"},
{:day=>"Tue", :time=>"03:30-18:15"},
{:day=>"Tue", :time=>"19:00-20:00"},
{:day=>"Wed", :time=>"04:25-15:14"},
{:day=>"Wed", :time=>"15:14-22:40"},
{:day=>"Thu", :time=>"00:00-23:59"},
{:day=>"Mon", :time=>"05:00-13:00"},
{:day=>"Mon", :time=>"15:00-21:00"}]
To calculate the free slots I first have to sort schedule_hash
by date and time. How to do so if both are just a string?
CodePudding user response:
You can do that as follows.
schedule_hash =[
{:day=>"Sun", :time=>"10:00-20:00"},
{:day=>"Fri", :time=>"05:00-10:00"},
{:day=>"Fri", :time=>"16:30-23:50"},
{:day=>"Sat", :time=>"10:00-24:00"},
{:day=>"Sun", :time=>"01:00-04:00"},
{:day=>"Sat", :time=>"02:00-06:00"},
{:day=>"Tue", :time=>"03:30-18:15"},
{:day=>"Tue", :time=>"19:00-20:00"},
{:day=>"Wed", :time=>"04:25-15:14"},
{:day=>"Wed", :time=>"15:14-22:40"},
{:day=>"Thu", :time=>"00:00-23:59"},
{:day=>"Mon", :time=>"05:00-13:00"},
{:day=>"Mon", :time=>"15:00-21:00"}
]
day_order = { "Sun"=>0, "Mon"=>1, "Tue"=>2, "Wed"=>3, "Thu"=>4, "Fri"=>5, "Sat"=>6 }
schedule_hash.sort_by { |h| [day_order[h[:day]], h[:time][0,5]] }
#=> [{:day=>"Sun", :time=>"01:00-04:00"},
# {:day=>"Sun", :time=>"10:00-20:00"},
# {:day=>"Mon", :time=>"05:00-13:00"},
# {:day=>"Mon", :time=>"15:00-21:00"},
# {:day=>"Tue", :time=>"03:30-18:15"},
# {:day=>"Tue", :time=>"19:00-20:00"},
# {:day=>"Wed", :time=>"04:25-15:14"},
# {:day=>"Wed", :time=>"15:14-22:40"},
# {:day=>"Thu", :time=>"00:00-23:59"},
# {:day=>"Fri", :time=>"05:00-10:00"},
# {:day=>"Fri", :time=>"16:30-23:50"},
# {:day=>"Sat", :time=>"02:00-06:00"},
# {:day=>"Sat", :time=>"10:00-24:00"}]
Enumerable#sort_by uses the method Array#<=> (the "spaceship operator") to sort arrays. See especially the third paragraph of the doc for <=>
.
Note that the arrays by which the elements of schedule_hash
are sorted are as follows.
schedule_hash.map { |h| [day_order[h[:day]], h[:time][0,5]] }
#=> [[0, "10:00"], [5, "05:00"], [5, "16:30"], [6, "10:00"],
# [0, "01:00"], [6, "02:00"], [2, "03:30"], [2, "19:00"],
# [3, "04:25"], [3, "15:14"], [4, "00:00"], [1, "05:00"],
# [1, "15:00"]]
CodePudding user response:
The Ruby class Date already has an array of abbreviated daynames with Date::ABBR_DAYNAMES
. You can use that (especially in Rails where it's already included - maybe don't add it solely for this purpose), but note that "Sun" is first, so if your target audience starts their week on a Monday, as most countries around the world do, you can call rotate
on the resulting array.
I would also probably separate the start time and end time of each appointment to make it easier to perform calculations on them later:
require 'date'
daynames = Date::ABBR_DAYNAMES
=> ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
# Turn splitted_dates to a hash with day, start time and end time of appointment
schedule_hash = splitted_dates.map do |(day, time)|
{ day: day, start_time: time[0..4], end_time: time[-5..-1] }
end
# Sort the hash by the index of the day name within "daynames", and then by start_time
sorted = schedule_hash.sort_by { |h| [daynames.index(h[:day]), h[:start_time]] }