Search code examples
javascriptarrayslodashchunks

Breaking available timeslot array into chunks based on booked slots


I have 2 arrays:

  1. generated timestamps (30 min each (1800 difference in each timestamp)) from particular start hour to end hour for a day.
  2. I get a booked slots response from the API response.

I need to merge both arrays to form the array of objects representing the available and booked slots:

let availableTimeslots = [
  1559709000,
  1559710800,
  1559712600,
  1559714400,
  1559716200,
  1559718000,
  1559719800,
  1559721600,
  1559723400,
  1559725200,
  1559727000,
  1559728800,
  1559730600,
  1559732400,
  1559734200,
  1559736000,
  1559737800,
  1559739600
];

let bookedTimeSlots = {
  bookings: [
    {
      timestamp: {
        from: 1559719800,
        to: 1559723400
      }
    },
    {
      timestamp: {
        from: 1559730600,
        to: 1559732400
      }
    }
  ]
};

I need to create array of objects, something like:

[
  {
    available: true,
    timeslots: [1559709000, 1559710800, 1559712600, 1559714400, 1559716200, 1559718000]
  },
  {
    available: false,
    timeslots: [1559719800, 1559721600, 1559723400]
  },
  {
    available: true,
    timeslots: [1559725200, 1559727000, 1559728800]
  },
  {
    available: false,
    timeslots: [1559730600, 1559732400]
  },
  {
    available: true,
    timeslots: [1559732400, 1559734200, 1559736000, 1559737800, 1559739600]
  }
];

I am really confused on how to proceed with this I am thinking on to replace the value in availableTimeslots with the desired booked slot object and later on all the non-object values with {available: true, timeslots: [...]}

bookedTimeSlots.bookings.map((bs, i)=> {
            let ai = availableTimeslots.findIndex(bs.timestamp.from);
            ai > -1 && (availableTimeslots[ai]={available: false, x  : [..._.range(bs.timestamp.from, bs.timestamp.to, 1800)]});
        })

Any help would be appreciated.


Solution

  • There's a lot of ways you could solve this. One way to simplify it is to take advantage of the fact that there's a known increment (1,800) between timeslots, so rather than trying slice up the array of timeslots, you can generate a new array of timeslots for each "chunk" given a start and end timeslot. In the below snippet you can see a basic recursive solution that takes this approach:

    const INCREMENT = 1800;
    
    // Utility function to generate an inclusive range
    function rangeIncl(start, end, incr = INCREMENT) {
      return start < end ? [start, ...rangeIncl(start + incr, end)] : [end];
    }
    
    function timeslotGroups(startTimeslot, endTimeslot, bookings) {
      const [booking, ...restBookings] = bookings;
    
      if (booking) {
        if (startTimeslot < booking.from) {
          // startTimeslot is before next booking.from; add available group
          return [
            {
              available: true,
              timeslots: rangeIncl(startTimeslot, booking.from - INCREMENT),
            },
            ...timeslotGroups(booking.from, endTimeslot, bookings),
          ];
        }
    
        if (startTimeslot <= booking.to) {
          // startTimeslot is between booking.from and .to; add not-available group
          return [
            {
              available: false,
              timeslots: rangeIncl(booking.from, booking.to),
            },
            ...timeslotGroups(booking.to + INCREMENT, endTimeslot, restBookings),
          ];
        }
    
        // startTimeslot is after booking.to; try again with next booking
        return timeslotGroups(startTimeslot, endTimeslot, restBookings);
      }
      
      // No more bookings; add final available group if there are any
      // timeslots left
      return startTimeslot < endTimeslot ? [
        {
          available: true,
          timeslots: rangeIncl(startTimeslot, endTimeslot),
        },
      ] : [];
    }
    
    const availableTimeslots = [
      1559709000, 1559710800, 1559712600, 1559714400, 1559716200, 1559718000,
      1559719800, 1559721600, 1559723400, 1559725200, 1559727000, 1559728800,
      1559730600, 1559732400, 1559734200, 1559736000, 1559737800, 1559739600,
    ];
    
    const bookedTimeslots = {
      bookings: [
        { timestamp: { from: 1559719800, to: 1559723400 }},
        { timestamp: { from: 1559730600, to: 1559732400 }},
      ],
    };
    
    const firstTimeslot = availableTimeslots[0];
    const lastTimeslot = availableTimeslots[availableTimeslots.length - 1];
    // Bookings will be easier to work with as an array of { from, to } objects
    const bookings = bookedTimeslots.bookings.map(booking => booking.
    timestamp);
    
    const groups = timeslotGroups(firstTimeslot, lastTimeslot, bookings);
    console.log(groups);

    Note that this code assumes that bookings will be in chronological order.