Home > Blockchain >  Group array of dates and format to schedule
Group array of dates and format to schedule

Time:02-02

I need to group an array of dates and then format the group of dates into a schedule format.

Possible labels could be:

  • Weekdays (from Mon to Fri)
  • Weekends (Sat and Sun)
  • Monday-Tuesday (range of days with same schedule)
  • Wednesday (specific day with unique schedule)
  • Thursday, Saturday (specific group of days with same schedule)

For example:

Input Data

[
  {
    day: "monday",
    start_time: "09:00",
    end_time: "18:00"
  },
  {
    day: "tuesday",
    start_time: "09:00",
    end_time: "18:00"
  },
  {
    day: "wednesday",
    start_time: "09:00",
    end_time: "18:00"
  },
  {
    id: 25,
    day: "thursday",
    start_time: "09:00",
    end_time: "18:00"
  },
  {
    day: "friday",
    start_time: "09:00",
    end_time: "18:00"
  },
  {
    day: "saturday",
    start_time: "10:00",
    end_time: "17:00"
  },
  {
    day: "sunday",
    start_time: "10:00",
    end_time: "17:00"
  }
]

Expected Output

[
  {
    label: 'All weekdays', // Mon-Fri
    value: '09:00 - 18:00',
  },
  {
    label: 'Weekend', // Sat-Sun
    value: '10:00 - 17:00',
  },
];

And the output can be as follows, if start_time and end_time are different for each day

[
  {
    label: 'Monday', // one day
    value: '09:00 - 20:00',
  },
  {
    label: 'Tuesday, Thursday', // specific days with same schedule
    value: '10:00 - 19:00',
  },
  {
    label: 'Wednesday', // one day
    value: '12:00 - 20:00',
  },
  {
    label: 'Friday - Sunday', // range of days with same schedule
    value: '10:00 - 17:00',
  },
];

CodeSandbox with template - link

CodePudding user response:

I have a similar solution on a project of mine, you could try to make any necessary changes to the code if you don't like the result.

You give an initial constants with an array of weekend and weekdays, and then comparing the inputed dated data you generate the desired output.

function formatDates(dates) {
const result = [];
const weekdays = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'];
const weekends = ['saturday', 'sunday'];
let start = 0;
let end = 0;

while (start < dates.length) {
let label = '';
let value = '';
let same = true;

end = start;
while (end < dates.length - 1 && same) {
  end  ;
  same = dates[end].start_time === dates[end - 1].start_time && dates[end].end_time === dates[end - 1].end_time;
}

if (weekdays.includes(dates[start].day) && weekdays.includes(dates[end].day)) {
  label = 'All weekdays';
  value = `${dates[start].start_time} - ${dates[start].end_time}`;
} else if (weekends.includes(dates[start].day) && weekends.includes(dates[end].day)) {
  label = 'Weekend';
  value = `${dates[start].start_time} - ${dates[start].end_time}`;
} else if (same) {
  if (weekdays.includes(dates[start].day)) {
    label = `${dates[start].day[0].toUpperCase()}${dates[start].day.slice(1)} - ${dates[end].day[0].toUpperCase()}${dates[end].day.slice(1)}`;
  } else if (weekends.includes(dates[start].day)) {
    label = `${dates[start].day[0].toUpperCase()}${dates[start].day.slice(1)} - ${dates[end].day[0].toUpperCase()}${dates[end].day.slice(1)}`;
  } else {
    label = `${dates[start].day[0].toUpperCase()}${dates[start].day.slice(1)}`;
  }
  value = `${dates[start].start_time} - ${dates[start].end_time}`;
} else {
  for (let i = start; i <= end; i  ) {
    result.push({
      label: `${dates[i].day[0].toUpperCase()}${dates[i].day.slice(1)}`,
      value: `${dates[i].start_time} - ${dates[i].end_time}`
    });
  }
}

if (label) {
  result.push({ label, value });
}

start = end   1;
}

return result;
}

CodePudding user response:

An approach for solving the OP's problem breaks down into ...

  • grouping/collecting all items (or day names) of a specific time-schedule/range
  • and creating the final result upon this first grouped and aggregated data,

... which one straightforwardly can implement by a reduce and a mapping task that would be accompanied by some helper functions which for example would ...

  • normalize any weekday's name
  • compare weekdays by their names
  • acquire the correct label of a time-schedule by e.g. an ordered list of unique weekday names.

The reduce task is going to create an object where each key already represent the final result's value, a string which represents a time range like e.g. '09:00 - 18:00' and where each of such a key's value is an array of each of the processed item's day-values (the latter being a string which represents a weekday's name with neither specific nor reliable latter-casing like e.g. 'monday' or 'Monday').

The map task would process the entries of such an above described object. Each entry's time-schedule related key gets assigned as the final items's value property. And each entry's weekday related value (an array of weekday names) is the base of computing the final item's label property.

Implementation ...

// helpers.
function normalizeNameOfWeekday(value) {
  return value
    .toLowerCase()
    .replace(/^(\p{L})(.*)$/u, (_, first, last) =>
      [first.toUpperCase(), last].join('')
    );
}
function compareWeekdaysByName(a, b) {
  const lookup = {
    monday: 0, tuesday: 1, wednesday: 2, 
    thursday: 3, friday: 4,
    saturday: 5, sunday: 6,
  };
  return lookup[a.toLowerCase()] - lookup[b.toLowerCase()];
}
function getTimeScheduleLabel(days) {
  const lookup = {
    monday_tuesday: 'Monday & Tuesday',
    monday_tuesday_wednesday: 'Monday - Wednesday',
    monday_tuesday_wednesday_thursday: 'Monday - Thursday',
    monday_tuesday_wednesday_thursday_friday: 'All weekdays',
    monday_tuesday_wednesday_thursday_friday_saturday: 'Monday - Saturday',
    monday_tuesday_wednesday_thursday_friday_saturday_sunday: 'Every day of the week',
    tuesday_wednesday: 'Tuesday & Wednesday',
    tuesday_wednesday_thursday: 'Tuesday - Thursday',
    tuesday_wednesday_thursday_friday: 'Tuesday - Friday',
    tuesday_wednesday_thursday_friday_saturday: 'Tuesday - Saturday',
    tuesday_wednesday_thursday_friday_saturday_sunday: 'Tuesday - Sunday',
    wednesday_thursday: 'Wednesday & Thursday',
    wednesday_thursday_friday: 'Wednesday - Friday',
    wednesday_thursday_friday_saturday: 'Wednesday - Saturday',
    wednesday_thursday_friday_saturday_sunday: 'Wednesday - Sunday',
    thursday_friday: 'Thursday & Friday',
    thursday_friday_saturday: 'Thursday - Saturday',
    thursday_friday_saturday_sunday: 'Thursday - Sunday',
    friday_saturday: 'Friday & Saturday',
    friday_saturday_sunday: 'Friday - Sunday',
    saturday_sunday: 'Weekend',
  };
  const scheduleFingerprint = [
    // set of unique day-names.
    ...new Set(days)
  ]
  // ordered list (of unique day-names).
  .sort(compareWeekdaysByName)
  // comparable schedule-fingerprint.
  .join('_').toLowerCase();

  return lookup[scheduleFingerprint] ?? days.map(normalizeNameOfWeekday).join(', ');
}

// reducer.
function collectDayOfSameTimeSchedule(index, { day, start_time, end_time }) {
  const scheduleKey = `${ start_time } - ${ end_time }`;

  // create and/or access the array of
  // day-names of the same time-schedule
  // and push another matching name into it.
  (index[scheduleKey] ??= []).push(day);
  
  return index;
}
// mapper.
function createTimeScheduleFromEntry([scheduleKey, listOfSameTimeScheduleDays]) {
  return {
    label: getTimeScheduleLabel(listOfSameTimeScheduleDays),
    value: scheduleKey,
  }
}

const sampleData_01 = [{
  day: "monday", start_time: "09:00", end_time: "18:00",
}, {
  day: "tuesday", start_time: "09:00", end_time: "18:00",
}, {
  day: "wednesday", start_time: "09:00", end_time: "18:00",
}, {
  id: 25, day: "thursday", start_time: "09:00", end_time: "18:00",
}, {
  day: "friday", start_time: "09:00", end_time: "18:00",
}, {
  day: "saturday", start_time: "10:00", end_time: "17:00",
}, {
  day: "sunday", start_time: "10:00", end_time: "17:00",
}];

const sampleData_02 = [{
  day: "monday", start_time: "09:00", end_time: "20:00",
}, {
  day: "tuesday", start_time: "10:00", end_time: "19:00",
}, {
  day: "wednesday", start_time: "12:00", end_time: "20:00",
}, {
  id: 25, day: "thursday", start_time: "10:00", end_time: "19:00",
}, {
  day: "friday", start_time: "10:00", end_time: "17:00",
}, {
  day: "saturday", start_time: "10:00", end_time: "17:00",
}, {
  day: "sunday", start_time: "10:00", end_time: "17:00",
}];

console.log(
  'sample-data with 2 time-schedules ...',
  Object
    .entries(
      sampleData_01
        .reduce(collectDayOfSameTimeSchedule, {})
    )
    .map(createTimeScheduleFromEntry)
);
console.log(
  'sample-data with 4 time-schedules ...',
  Object
    .entries(
      sampleData_02
        .reduce(collectDayOfSameTimeSchedule, {})
    )
    .map(createTimeScheduleFromEntry)
);
console.log('\n');

console.log(
  'intermediate reducer-step of ... sample-data with 2 time-schedules ...',
  sampleData_01
    .reduce(collectDayOfSameTimeSchedule, {})
);
console.log(
  'intermediate reducer-step of ... sample-data with 4 time-schedules ...',
  sampleData_02
    .reduce(collectDayOfSameTimeSchedule, {})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

  • Related