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.
Advertisement
Answer
Firstly one needs to separate the
dayvalue from thehoursvalue part of a single opening hours string.This either can be achieved via
indexOf,substringandtrim…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*/ … andslice-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
mapan entire array of opening hours strings into an array of arrays, where each array-item contains thedayvalue as first and thehoursvalue as second array item … either like this …sampleList.map(splitOpeningHoursEntry);
… or like that …
sampleList.map(regexSplitOpeningHoursEntry);
On top one needs to
reducethis array of splitted[<day>, <hours>]entries into its compact form …Finally one has to
mapeach 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; }