0

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

2
  • Thanks for the question. Please always remember to mention your programming language and library (if any) in the body of the question and add appropriate tags. I made an attempt at the tags, please correct and improve since I probably didn’t find the best. Commented Jan 28, 2023 at 10:32
  • This is a homework assignment, you should do your own assignments. Commented Feb 5, 2023 at 13:42

3 Answers 3

1
+50

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 working days',
    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: 'All 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; }

Sign up to request clarification or add additional context in comments.

5 Comments

Not for a technical fault. It's a homework assignment. People should solve their own homework assignments.
@john-jones ... how does one know whether it's a homework assignment or not?
He just says he needs a program that does x. That's not a question, that's an assignment. Either homework assignment or somebody is paying him. Or he's just doing an assignment like that for fun. Doesn't matter which one is the case he should always just do it himself. Or pay. I don't think we are helping him by doing his work for him.
I tried to undo the downvote but can't until it has changed.
@john-jones ... It's all right, I can live with it. After all I now know the reason. And it's a legit opinion/vote though.
-2

I have written a snippet, it might help

        var scheduleInfo = [
    {
        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: "08: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"
    }
]

var tempOutput = [];
var output = [];

let allDays = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
var weekdays = ["monday", "tuesday", "wednesday", "thursday", "friday"]
weekdays = weekdays.sort();

//sort according to schedule
for (let i in scheduleInfo) {
    let sch = scheduleInfo[i];
    if (!allValue.includes(sch.start_time + sch.end_time)) {
        allValue.push(sch.start_time + sch.end_time);
        tempOutput.push({
            label: sch.day,
            start_time: sch.start_time,
            end_time: sch.end_time
        })
    } else {
        for (let j in tempOutput) {
            if (tempOutput[j].start_time === sch.start_time && tempOutput[j].end_time === sch.end_time) {
                tempOutput[j].label = tempOutput[j].label + ',' + sch.day;
            }
        }
    }
}

//logic to identify label.
for (let i in tempOutput) {
    var days = tempOutput[i].label.split(",");
    var label = days[0];
    var tempLDay = "";
    for (let j = 1; j < days.length; j++) {
        if (!tempLDay) {
            label += days[j];
            tempLDay = days[j];
        }
        //check for consecutive days
        let daysDiff = allDays.indexOf(days[j - 1]) % 7 - allDays.indexOf(days[j]) % 7;
        if (daysDiff == -1 || daysDiff === 1) {
            label = label.replace(tempLDay, "-" + days[j]);
            tempLDay = "-" + days[j]
        } else {
            label += "," + days[j]
            tempLDay = "";
        }
    }
    if (label == "monday-friday") {
        label = "All weekdays"
    } else if (label == "saturday-sunday") {
        label = "Weekend"
    }
    output.push({
        label: label,
        value: tempOutput[i].start_time + ' - ' + tempOutput[i].end_time
    })
}

console.log(output);

3 Comments

Has the above presented solution ever been tested by its creator? Hint ... What is allValue supposed to be? Where does it for instance get defined? The code as it is now just throws an error.
allValue is a temporary array to look for all combinations of unique start times and end times. You could assign it as an empty array at the beginning of the first for loop. This code can be used to achieve the requirements. One more extra thing to add would be to check for an object that doesn't have consecutive days, then the array needs sorting based on the days of the week.
Then just provide the answer exactly as you just explained it because the audience does neither know your tries, nor your approach/intention. But it misses some explanation and/or more detailed (code) comments and of cause an error free running example code.
-3

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;
}

1 Comment

Has the above presented solution ever been tested by its creator with at least the two scenarios that the OP did provide?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.