I have an array of string items ...
[
'Mon : 9:00AM - 7:00PM',
'Tue : 9:00AM - 10:00PM',
'Wed : Closed',
'Thu : 9:00AM - 7:00PM',
'Fri : 9:00AM - 7:00PM',
'Sat : Closed',
'Sun : Closed',
]
... and I want to achieve a result like the one below ...
[
'Mon: 9:00AM - 7:00PM',
'Tue: 9:00AM - 10:00PM',
'Wed: Closed',
'Thu-Fri: 9:00AM - 7:00PM',
'Sat-Sun: Closed',
]
Any help is really appreciated.
Firstly one needs to separate the day
value from the hours
value part of a single opening hours string.
This either can be achieved via indexOf
, substring
and trim
...
function splitOpeningHoursEntry(entry) {
// e.g.: 'Mon : 9:00AM - 7:00PM'
const indexOfColon = entry.indexOf(':'); // e.g. 5
// entry.substring(0, 5) ... e.g.: 'Mon '
const day = entry.substring(0, indexOfColon);
// entry.substring(6) ... e.g.: ' 9:00AM - 7:00PM'
const hours = entry.substring(indexOfColon + 1);
// e.g.: ['Mon', '9:00AM - 7:00PM']
return [day.trim(), hours.trim()];
}
... or it can be done by split
-ting with a Regular Expression like ... /(^[^:\s]+)\s*:\s*/ ... and slice
-ing the results array ...
function regexSplitOpeningHoursEntry(entry) {
// [https://regex101.com/r/vGRck7/3]
// entry.split(':') // ["Mon ", " 9", "00AM - 7", "00PM"]
// [https://regex101.com/r/vGRck7/2]
// entry.split(/\s*:\s*/) // ["Mon", "9", "00AM - 7", "00PM"]
// [https://regex101.com/r/vGRck7/1]
// entry.split(/(^[^:\s]+)\s*:\s*/) // ["", "Mon", "9:00AM - 7:00PM"];
return entry.split(/(^[^:\s]+)\s*:\s*/).slice(1);
}
Then one has to map
an entire array of opening hours strings into an array of arrays, where each array-item contains the day
value as first and the hours
value as second array item ... either like this ...
sampleList.map(splitOpeningHoursEntry);
... or like that ...
sampleList.map(regexSplitOpeningHoursEntry);
On top one needs to reduce
this array of splitted [<day>, <hours>]
entries into its compact form ...
Finally one has to map
each splitted [<day>, <hours>]
entry with a concatenation task back into its human readable string form....
const sampleList = [
'Mon : 9:00AM - 7:00PM',
'Tue : 9:00AM - 10:00PM',
'Wed : Closed',
'Thu : 9:00AM - 7:00PM',
'Fri : 9:00AM - 7:00PM',
'Sat : Closed',
'Sun : Closed',
];
function splitOpeningHoursEntry(entry) {
// e.g.: 'Mon : 9:00AM - 7:00PM'
const indexOfColon = entry.indexOf(':'); // e.g. 5
// entry.substring(0, 5) ... e.g.: 'Mon '
const day = entry.substring(0, indexOfColon);
// entry.substring(6) ... e.g.: ' 9:00AM - 7:00PM'
const hours = entry.substring(indexOfColon + 1);
// e.g.: ['Mon', '9:00AM - 7:00PM']
return [day.trim(), hours.trim()];
}
function regexSplitOpeningHoursEntry(entry) {
// [https://regex101.com/r/vGRck7/3]
// entry.split(':') // ["Mon ", " 9", "00AM - 7", "00PM"]
// [https://regex101.com/r/vGRck7/2]
// entry.split(/\s*:\s*/) // ["Mon", "9", "00AM - 7", "00PM"]
// [https://regex101.com/r/vGRck7/1]
// entry.split(/(^[^:\s]+)\s*:\s*/) // ["", "Mon", "9:00AM - 7:00PM"];
return entry.split(/(^[^:\s]+)\s*:\s*/).slice(1);
}
function compactOpeningHoursEntries(compactEntries, splitEntry, idx, arr) {
// get the predecessor item of the currently
// processed `splitEntry` item or default to [].
const prevSplitEntry = arr[idx - 1] || [];
// get the successor item of the currently
// processed `splitEntry` item or default to [].
const nextSplitEntry = arr[idx + 1] || [];
if (prevSplitEntry[1] !== splitEntry[1]) {
// in case the previous and current `hours` values do not match ...
// ... push the current entry of splitted `day` and `hours`
// values into `compactEntries` which is the accumulating
// array of the compacted form of all opening hours entries.
compactEntries.push(splitEntry);
} else if (nextSplitEntry[1] !== splitEntry[1]) {
// ... or in case the next and current `hours` values do not match ...
const lastCompactEntry = compactEntries[compactEntries.length - 1];
// ...retrieve the first and the last day value
// of a compactly written day-range format...
const firstDayInRange = lastCompactEntry[0];
const lastDayInRange = splitEntry[0];
// ...and create and rewrite its compact form
// as the compacted entry's final day value.
lastCompactEntry[0] = firstDayInRange + '-' + lastDayInRange;
}
return compactEntries;
}
function concatOpeningHoursEntry([day, hours]) {
return `${ day }: ${ hours }`;
}
// First one needs to separate the `day` from the
// `hours` part of a single opening hours string
console.log(
"splitOpeningHoursEntry('Mon : 9:00AM - 7:00PM') ...",
splitOpeningHoursEntry('Mon : 9:00AM - 7:00PM')
);
console.log(
"regexSplitOpeningHoursEntry('Mon : 9:00AM - 7:00PM') ...",
regexSplitOpeningHoursEntry('Mon : 9:00AM - 7:00PM')
);
// Then one does map an entire array of opening hours strings
// into an array of arrays, where each array item contains the
// `day` value as first and the `hours` value as second array item.
console.log(
'... list item `split` mapping ... ',
sampleList
.map(splitOpeningHoursEntry)
//.map(regexSplitOpeningHoursEntry)
)
// On top one has to `reduce` this array of splitted
// `[<day>, <hours>]` entries into its compact form.
console.log(
'... list item `split` mapping and split entry reducing ... ',
sampleList
.map(splitOpeningHoursEntry)
.reduce(compactOpeningHoursEntries, [])
);
// Finally one needs to `map` each splitted `[<day>, <hours>]` entry
// with a concatenation task back into its human readable string form.
console.log(
'... list item `split` mapping, reducing and a final concatenation mapping ... ',
sampleList
.map(splitOpeningHoursEntry)
.reduce(compactOpeningHoursEntries, [])
.map(concatOpeningHoursEntry)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Another less talkative proof of concept ...
function splitOpeningHoursEntry(entry) {
return entry.split(/(^[^:\s]+)\s*:\s*/).slice(1);
}
function concatOpeningHoursEntry([day, hours]) {
return `${ day }: ${ hours }`;
}
function compactOpeningHoursEntries(compactEntries, splitEntry, idx, arr) {
const prevSplitEntry = arr[idx - 1] || [];
const nextSplitEntry = arr[idx + 1] || [];
if (prevSplitEntry[1] !== splitEntry[1]) {
compactEntries.push(splitEntry);
} else if (nextSplitEntry[1] !== splitEntry[1]) {
const lastCompactEntry = compactEntries[compactEntries.length - 1];
const firstDayInRange = lastCompactEntry[0];
const lastDayInRange = splitEntry[0];
lastCompactEntry[0] = firstDayInRange + '-' + lastDayInRange;
}
return compactEntries;
}
console.log([
'Mon : 08:00AM - 17:00PM',
'Tue : 08:00AM - 17:00PM',
'Wed : 08:00AM - 17:00PM',
'Thu : 10:00AM - 14:00PM',
'Fri : 10:00AM - 14:00PM',
'Sat : Closed',
'Sun : Closed',
], '=>', [
'Mon : 08:00AM - 17:00PM',
'Tue : 08:00AM - 17:00PM',
'Wed : 08:00AM - 17:00PM',
'Thu : 10:00AM - 14:00PM',
'Fri : 10:00AM - 14:00PM',
'Sat : Closed',
'Sun : Closed',
]
.map(splitOpeningHoursEntry)
.reduce(compactOpeningHoursEntries, [])
.map(concatOpeningHoursEntry)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }